test: Cut not_equal
This commit is contained in:
parent
229a8bbc3c
commit
2fcab52f65
7 changed files with 75 additions and 18 deletions
|
@ -7,7 +7,7 @@ import prolog.ast.terms.Functor
|
|||
import prolog.ast.terms.Goal
|
||||
import prolog.ast.terms.Head
|
||||
import prolog.builtins.True
|
||||
import prolog.exceptions.AppliedCut
|
||||
import prolog.flags.AppliedCut
|
||||
import prolog.logic.unifyLazy
|
||||
|
||||
/**
|
||||
|
@ -36,7 +36,11 @@ abstract class Clause(private val head: Head, private val body: Body) : Resolven
|
|||
onFailure = { error ->
|
||||
if (error is AppliedCut) {
|
||||
// Find single solution and return immediately
|
||||
yield(Result.failure(AppliedCut(newHeadSubs + error.subs)))
|
||||
if (error.subs != null) {
|
||||
yield(Result.failure(AppliedCut(newHeadSubs + error.subs)))
|
||||
} else {
|
||||
yield(Result.failure(AppliedCut()))
|
||||
}
|
||||
return@sequence
|
||||
} else {
|
||||
yield(Result.failure(error))
|
||||
|
|
|
@ -4,7 +4,7 @@ import prolog.Answers
|
|||
import prolog.Substitutions
|
||||
import prolog.ast.terms.Functor
|
||||
import prolog.ast.terms.Goal
|
||||
import prolog.exceptions.AppliedCut
|
||||
import prolog.flags.AppliedCut
|
||||
|
||||
/**
|
||||
* Collection of [Clause]s with the same [Functor].
|
||||
|
@ -62,8 +62,10 @@ class Predicate : Resolvent {
|
|||
},
|
||||
onFailure = {
|
||||
if (it is AppliedCut) {
|
||||
// If it's a cut, yield the result with the left substitutions
|
||||
yield(Result.failure(AppliedCut(it.subs)))
|
||||
if (it.subs != null) {
|
||||
// If it's a cut, yield the result with the left substitutions
|
||||
yield(Result.success(it.subs))
|
||||
}
|
||||
return@sequence
|
||||
} else {
|
||||
yield(Result.failure(it))
|
||||
|
|
|
@ -7,7 +7,7 @@ import prolog.ast.terms.Atom
|
|||
import prolog.ast.terms.Body
|
||||
import prolog.ast.terms.Goal
|
||||
import prolog.ast.logic.LogicOperator
|
||||
import prolog.exceptions.AppliedCut
|
||||
import prolog.flags.AppliedCut
|
||||
|
||||
/**
|
||||
* Always fail.
|
||||
|
@ -56,13 +56,17 @@ class Conjunction(private val left: LogicOperand, private val right: LogicOperan
|
|||
// If the right part fails, check if it's a cut
|
||||
onFailure = { exception ->
|
||||
if (exception is AppliedCut) {
|
||||
// If it's a cut, yield the result with the left substitutions
|
||||
yield(Result.failure(AppliedCut(leftSubs + exception.subs)))
|
||||
if (exception.subs != null) {
|
||||
// If it's a cut, yield the result with the left substitutions
|
||||
yield(Result.failure(AppliedCut(leftSubs + exception.subs)))
|
||||
} else {
|
||||
yield(Result.failure(AppliedCut()))
|
||||
}
|
||||
return@sequence
|
||||
} else {
|
||||
// If it's not a cut, yield the failure
|
||||
yield(Result.failure(exception))
|
||||
}
|
||||
|
||||
// If it's not a cut, yield the failure
|
||||
yield(Result.failure(exception))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -71,7 +75,7 @@ class Conjunction(private val left: LogicOperand, private val right: LogicOperan
|
|||
onFailure = { exception ->
|
||||
// 1. If the left part is a cut, satisfy the right part ONCE, and stop searching for more solutions
|
||||
if (exception is AppliedCut) {
|
||||
right.satisfy(subs + exception.subs).first().fold(
|
||||
right.satisfy(subs + (exception.subs!!)).firstOrNull()?.fold(
|
||||
onSuccess = {
|
||||
// If the right part succeeds, yield the result with the left substitutions
|
||||
yield(Result.success(exception.subs + it))
|
||||
|
@ -81,7 +85,7 @@ class Conjunction(private val left: LogicOperand, private val right: LogicOperan
|
|||
// If the right part fails, yield the failure
|
||||
yield(Result.failure(it))
|
||||
}
|
||||
)
|
||||
) ?: yield(Result.failure(AppliedCut()))
|
||||
} else {
|
||||
// 2. Any other failure should be returned as is
|
||||
yield(Result.failure(exception))
|
||||
|
|
|
@ -12,6 +12,19 @@ import prolog.ast.terms.Operator
|
|||
import prolog.ast.terms.Term
|
||||
import prolog.logic.applySubstitution
|
||||
import prolog.logic.equivalent
|
||||
import prolog.logic.unifyLazy
|
||||
|
||||
/**
|
||||
* Unify Term1 with Term2. True if the unification succeeds.
|
||||
*/
|
||||
class Unify(private val term1: Term, private val term2: Term): Operator(Atom("="), term1, term2) {
|
||||
override fun satisfy(subs: Substitutions): Answers = sequence {
|
||||
val t1 = applySubstitution(term1, subs)
|
||||
val t2 = applySubstitution(term2, subs)
|
||||
|
||||
yieldAll(unifyLazy(t1, t2, subs))
|
||||
}
|
||||
}
|
||||
|
||||
class Equivalent(private val term1: Term, private val term2: Term) : Operator(Atom("=="), term1, term2) {
|
||||
override fun satisfy(subs: Substitutions): Answers = sequence {
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
package prolog.exceptions
|
||||
|
||||
import prolog.Substitutions
|
||||
|
||||
class AppliedCut(val subs: Substitutions): Exception()
|
11
src/prolog/flags/AppliedCut.kt
Normal file
11
src/prolog/flags/AppliedCut.kt
Normal file
|
@ -0,0 +1,11 @@
|
|||
package prolog.flags
|
||||
|
||||
import prolog.Substitutions
|
||||
|
||||
/**
|
||||
* An exception that indicates that a cut has been applied in the Prolog engine.
|
||||
*
|
||||
* @param subs The substitutions that were in effect when the cut was applied.
|
||||
* If null, it means that the cut was applied on a failed branch.
|
||||
*/
|
||||
class AppliedCut(val subs: Substitutions? = null): Throwable()
|
Reference in a new issue