Call & Ignore

This commit is contained in:
Tibo De Peuter 2025-05-09 08:36:11 +02:00
parent 9b454a9669
commit 5bfeb96176
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
7 changed files with 118 additions and 28 deletions

View file

@ -114,7 +114,20 @@ class Conjunction(val left: LogicOperand, private val right: LogicOperand) :
open class Disjunction(private val left: LogicOperand, private val right: LogicOperand) :
LogicOperator(Atom(";"), left, right) {
override fun satisfy(subs: Substitutions): Answers = sequence {
yieldAll(left.satisfy(subs))
left.satisfy(subs).forEach { left ->
left.fold(
onSuccess = { leftSubs ->
yield(Result.success(leftSubs))
},
onFailure = { failure ->
if (failure is AppliedCut) {
val leftSubs = failure.subs
yield(Result.failure(AppliedCut(leftSubs)))
return@sequence
}
}
)
}
yieldAll(right.satisfy(subs))
}

View file

@ -10,15 +10,12 @@ import prolog.ast.terms.Operator
import prolog.ast.terms.Term
class Member(private val element: Term, private val list: List) : Operator(Atom("member"), element, list) {
private var solution: Operator = if (list is Empty) {
Unify(element, list)
} else if (list is Cons) {
Disjunction(
private var solution: Operator = when (list) {
is Empty -> Disjunction(Fail, Fail)
is Cons -> Disjunction(
Unify(element, list.head),
Member(element, list.tail)
)
} else {
throw IllegalArgumentException("Invalid list type: ${list::class.simpleName}")
}
override fun satisfy(subs: Substitutions): Answers = solution.satisfy(subs)

View file

@ -0,0 +1,39 @@
package prolog.builtins
import prolog.Answers
import prolog.Substitutions
import prolog.ast.terms.Atom
import prolog.ast.terms.Goal
import prolog.ast.terms.Operator
import prolog.flags.AppliedCut
class Call(private val goal: Goal) : Operator(Atom("call"), null, goal) {
override fun satisfy(subs: Substitutions): Answers = goal.satisfy(subs)
}
/**
* Calls [Goal] once, but succeeds, regardless of whether Goal succeeded or not.
*/
class Ignore(goal: Goal) : Operator(Atom("ignore"), null, goal) {
private val disjunction = Disjunction(
Conjunction(Call(goal), Cut()),
True
)
override fun satisfy(subs: Substitutions): Answers = sequence {
disjunction.satisfy(subs).forEach { result ->
result.fold(
onSuccess = { newSubs ->
yield(Result.success(newSubs))
},
onFailure = { failure ->
if (failure is AppliedCut && failure.subs != null) {
yield(Result.success(failure.subs))
} else {
yield(Result.failure(failure))
}
}
)
}
}
}

View file

@ -7,12 +7,11 @@ import prolog.ast.arithmetic.Expression
import prolog.ast.arithmetic.Float
import prolog.ast.arithmetic.Integer
import prolog.ast.arithmetic.Number
import prolog.ast.lists.List
import prolog.ast.lists.List.Cons
import prolog.ast.lists.List.Empty
import prolog.ast.logic.Fact
import prolog.ast.logic.LogicOperator
import prolog.ast.terms.*
import prolog.ast.lists.List as PList
// Apply substitutions to a term
fun applySubstitution(term: Term, subs: Substitutions): Term = when {
@ -29,16 +28,8 @@ fun applySubstitution(term: Term, subs: Substitutions): Term = when {
else -> term
}
//TODO Combine with the other applySubstitution function
fun applySubstitution(expr: Expression, subs: Substitutions): Expression = when {
variable(expr, emptyMap()) -> applySubstitution(expr as Term, subs) as Expression
atomic(expr, subs) -> expr
expr is LogicOperator -> {
expr.arguments = expr.arguments.map { applySubstitution(it, subs) }
expr
}
else -> expr
fun applySubstitution(expr: Expression, subs: Substitutions): Expression {
return applySubstitution(expr as Term, subs) as Expression
}
// Check if a variable occurs in a term
@ -90,7 +81,7 @@ fun unifyLazy(term1: Term, term2: Term, subs: Substitutions): Answers = sequence
}
}
t1 is List && t2 is List -> {
t1 is PList && t2 is PList -> {
if (equivalent(t1, t2, subs)) {
yield(Result.success(emptyMap()))
} else if (t1.size == t2.size) {
@ -120,8 +111,8 @@ fun unifyLazy(term1: Term, term2: Term, subs: Substitutions): Answers = sequence
}
private fun unifyArgs(
args1: kotlin.collections.List<Argument>,
args2: kotlin.collections.List<Argument>,
args1: List<Argument>,
args2: List<Argument>,
subs: Substitutions
): Answers = sequence {
// Using the current subs, unify the first argument of each list
@ -171,7 +162,7 @@ fun equivalent(term1: Term, term2: Term, subs: Substitutions): Boolean {
term1 is Variable && term2 is Variable -> term1 == term2
term1 is Variable -> term1 in subs && equivalent(subs[term1]!!, term2, subs)
term2 is Variable -> term2 in subs && equivalent(subs[term2]!!, term1, subs)
term1 is List && term2 is List -> {
term1 is PList && term2 is PList -> {
if (term1.isEmpty() && term2.isEmpty()) {
true
} else if (term1.isEmpty() || term2.isEmpty()) {