51 lines
1.6 KiB
Kotlin
51 lines
1.6 KiB
Kotlin
package prolog.builtins
|
|
|
|
import prolog.Answers
|
|
import prolog.Substitutions
|
|
import prolog.ast.terms.Goal
|
|
import prolog.ast.terms.Operator
|
|
import prolog.ast.terms.Term
|
|
import prolog.flags.AppliedCut
|
|
import prolog.logic.applySubstitution
|
|
|
|
class Call(private val goal: Term) : Operator("call", rightOperand = goal) {
|
|
override fun satisfy(subs: Substitutions): Answers {
|
|
val appliedGoal = applySubstitution(goal, subs) as Goal
|
|
return appliedGoal.satisfy(subs)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Make a possibly nondeterministic [Goal] semideterministic, i.e. succeed at most once.
|
|
*/
|
|
class Once(private val goal: Term) : Operator("once", rightOperand = goal) {
|
|
private val conjunction = Conjunction(Call(goal), Cut())
|
|
override fun satisfy(subs: Substitutions): Answers = conjunction.satisfy(subs).take(1)
|
|
}
|
|
|
|
/**
|
|
* Calls [Goal] once, but succeeds, regardless of whether Goal succeeded or not.
|
|
*/
|
|
class Ignore(goal: Term) : Operator("ignore", rightOperand = 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))
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|