Call & Ignore
This commit is contained in:
parent
9b454a9669
commit
5bfeb96176
7 changed files with 118 additions and 28 deletions
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
39
src/prolog/builtins/metaOperators.kt
Normal file
39
src/prolog/builtins/metaOperators.kt
Normal 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))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()) {
|
||||
|
|
Reference in a new issue