refactor: Herstructurering

This commit is contained in:
Tibo De Peuter 2025-04-06 19:16:50 +02:00
parent 1acd1cfb67
commit e3c84e1761
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
33 changed files with 290 additions and 178 deletions

86
src/prolog/logic/unify.kt Normal file
View 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()
}
}