refactor: Herstructurering
This commit is contained in:
parent
1acd1cfb67
commit
e3c84e1761
33 changed files with 290 additions and 178 deletions
86
src/prolog/logic/unify.kt
Normal file
86
src/prolog/logic/unify.kt
Normal file
|
@ -0,0 +1,86 @@
|
|||
package prolog.logic
|
||||
|
||||
import prolog.ast.terms.Structure
|
||||
import prolog.ast.terms.Term
|
||||
import prolog.ast.terms.Variable
|
||||
import prolog.builtins.atomic
|
||||
import prolog.builtins.compound
|
||||
import prolog.builtins.equivalent
|
||||
import prolog.builtins.variable
|
||||
import java.util.*
|
||||
|
||||
typealias Substituted = Map<Variable, Term>
|
||||
|
||||
// Apply substitutions to a term
|
||||
private fun applySubstitution(term: Term, substitution: Substituted): Term = when {
|
||||
variable(term) -> substitution[(term as Variable)] ?: term
|
||||
atomic(term) -> term
|
||||
compound(term) -> {
|
||||
val structure = term as Structure
|
||||
Structure(structure.name, structure.arguments.map { applySubstitution(it, substitution) })
|
||||
}
|
||||
else -> term
|
||||
}
|
||||
|
||||
// Check if a variable occurs in a term
|
||||
private fun occurs(variable: Variable, term: Term): Boolean = when {
|
||||
variable(term) -> term == variable
|
||||
atomic(term) -> false
|
||||
compound(term) -> {
|
||||
val structure = term as Structure
|
||||
structure.arguments.any { occurs(variable, it) }
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
// Generate possible substitutions
|
||||
private fun generateSubstitutions(term1: Term, term2: Term, subs: Substituted): Sequence<Substituted> = sequence {
|
||||
val t1 = applySubstitution(term1, subs)
|
||||
val t2 = applySubstitution(term2, subs)
|
||||
|
||||
when {
|
||||
equivalent(t1, t2) -> yield(subs)
|
||||
variable(t1) -> {
|
||||
val variable = t1 as Variable
|
||||
if (!occurs(variable, t2)) {
|
||||
variable.bind(t2)
|
||||
yield(subs + (variable to t2))
|
||||
}
|
||||
}
|
||||
variable(t2) -> {
|
||||
val variable = t2 as Variable
|
||||
if (!occurs(variable, t1)) {
|
||||
variable.bind(t1)
|
||||
yield(subs + (variable to t1))
|
||||
}
|
||||
}
|
||||
compound(t1) && compound(t2) -> {
|
||||
val structure1 = t1 as Structure
|
||||
val structure2 = t2 as Structure
|
||||
if (structure1.functor == structure2.functor) {
|
||||
val newSubstitution = structure1.arguments.zip(structure2.arguments).fold(subs) { acc, (arg1, arg2) ->
|
||||
generateSubstitutions(arg1, arg2, acc).firstOrNull() ?: return@sequence
|
||||
}
|
||||
yield(newSubstitution)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
// Unify two terms with backtracking and lazy evaluation
|
||||
fun unifyLazy(term1: Term, term2: Term, subs: Substituted): Sequence<Substituted> = sequence {
|
||||
generateSubstitutions(term1, term2, subs).forEach { newSubs ->
|
||||
// Return the new substitution
|
||||
yield(newSubs)
|
||||
}
|
||||
}
|
||||
|
||||
fun unify(term1: Term, term2: Term): Optional<Substituted> {
|
||||
val substitutions = unifyLazy(term1, term2, emptyMap()).toList()
|
||||
return if (substitutions.isNotEmpty()) {
|
||||
Optional.of(substitutions.first())
|
||||
} else {
|
||||
Optional.empty()
|
||||
}
|
||||
}
|
Reference in a new issue