refactor: Rework
This commit is contained in:
parent
ac55ed4c64
commit
6469dd6ced
34 changed files with 593 additions and 552 deletions
|
@ -1,10 +1,11 @@
|
|||
package prolog.builtins
|
||||
|
||||
import prolog.Answers
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.arithmetic.ArithmeticOperator
|
||||
import prolog.ast.arithmetic.Expression
|
||||
import prolog.ast.logic.LogicOperand
|
||||
import prolog.ast.logic.LogicOperator
|
||||
import prolog.ast.logic.Provable
|
||||
import prolog.ast.arithmetic.Simplification
|
||||
import prolog.ast.logic.Satisfiable
|
||||
import prolog.ast.terms.*
|
||||
import prolog.logic.*
|
||||
|
||||
|
@ -20,20 +21,20 @@ import prolog.logic.*
|
|||
* True if expression Expr1 evaluates to a number non-equal to Expr2.
|
||||
*/
|
||||
class EvaluatesToDifferent(private val left: Expression, private val right: Expression) :
|
||||
ArithmeticOperator(Atom("=\\="), left, right) {
|
||||
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
|
||||
val t1 = left.evaluate(subs)
|
||||
val t2 = right.evaluate(subs)
|
||||
Operator(Atom("=\\="), left, right), Satisfiable {
|
||||
override fun satisfy(subs: Substitutions): Answers {
|
||||
val t1 = left.simplify(subs)
|
||||
val t2 = right.simplify(subs)
|
||||
|
||||
// Should both be instantiated
|
||||
if (!atomic(t1.first) || !atomic(t2.first)) {
|
||||
throw IllegalArgumentException("Both operands must be instantiated")
|
||||
if (!atomic(t1.to, subs) || !atomic(t2.to, subs)) {
|
||||
return sequenceOf(Result.failure(IllegalArgumentException("Both operands must be instantiated")))
|
||||
}
|
||||
|
||||
return if (equivalent(t1.first, t2.first)) {
|
||||
Pair(False, emptyMap())
|
||||
return if (equivalent(t1.to, t2.to, subs)) {
|
||||
emptySequence()
|
||||
} else {
|
||||
Pair(True, t1.second + t2.second)
|
||||
sequenceOf(Result.success(emptyMap()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,21 +44,17 @@ class EvaluatesToDifferent(private val left: Expression, private val right: Expr
|
|||
* True if Expr1 evaluates to a number equal to Expr2.
|
||||
*/
|
||||
class EvaluatesTo(private val left: Expression, private val right: Expression) :
|
||||
ArithmeticOperator(Atom("=:="), left, right) {
|
||||
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
|
||||
val t1 = left.evaluate(subs)
|
||||
val t2 = right.evaluate(subs)
|
||||
Operator(Atom("=:="), left, right) {
|
||||
override fun satisfy(subs: Substitutions): Answers {
|
||||
val t1 = left.simplify(subs)
|
||||
val t2 = right.simplify(subs)
|
||||
|
||||
// Should both be instantiated
|
||||
if (!atomic(t1.first) || !atomic(t2.first)) {
|
||||
throw IllegalArgumentException("Both operands must be instantiated")
|
||||
if (!atomic(t1.to, subs) || !atomic(t2.to, subs)) {
|
||||
return sequenceOf(Result.failure(IllegalArgumentException("Both operands must be instantiated")))
|
||||
}
|
||||
|
||||
return if (equivalent(t1.first, t2.first)) {
|
||||
Pair(True, t1.second + t2.second)
|
||||
} else {
|
||||
Pair(False, emptyMap())
|
||||
}
|
||||
return if (equivalent(t1.to, t2.to, subs)) sequenceOf(Result.success(emptyMap())) else emptySequence()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,16 +62,20 @@ class EvaluatesTo(private val left: Expression, private val right: Expression) :
|
|||
* True when Number is the value to which Expr evaluates.
|
||||
*/
|
||||
class Is(private val left: Expression, private val right: Expression) :
|
||||
Operator(Atom("is"), left, right), Provable {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> {
|
||||
val t1 = left.evaluate(subs)
|
||||
val t2 = right.evaluate(subs)
|
||||
Operator(Atom("is"), left, right), Satisfiable {
|
||||
override fun satisfy(subs: Substitutions): Answers {
|
||||
val t1 = left.simplify(subs)
|
||||
val t2 = right.simplify(subs)
|
||||
|
||||
if (!atomic(t2.first)) {
|
||||
throw IllegalArgumentException("Arguments are not sufficiently instantiated")
|
||||
if (!atomic(t2.to, subs)) {
|
||||
return sequenceOf(Result.failure(IllegalArgumentException("Right operand must be instantiated")))
|
||||
}
|
||||
|
||||
return unifyLazy(t1.first, t2.first, subs).map{ it + t1.second + t2.second }
|
||||
if (!variable(t1.to, subs) && equivalent(t1.to, t2.to, subs + listOfNotNull(t1.mapped, t2.mapped))) {
|
||||
return sequenceOf(Result.success(emptyMap()))
|
||||
}
|
||||
|
||||
return unifyLazy(t1.to, t2.to, subs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,10 +94,11 @@ class Positive(operand: Expression) : Add(Integer(0), operand)
|
|||
*/
|
||||
open class Add(private val expr1: Expression, private val expr2: Expression) :
|
||||
ArithmeticOperator(Atom("+"), expr1, expr2) {
|
||||
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
|
||||
override fun simplify(subs: Substitutions): Simplification {
|
||||
val result = Variable("Result")
|
||||
val map = plus(expr1, expr2, result, subs)
|
||||
return result.evaluate(map.first().getOrThrow())
|
||||
val simplification = result.simplify(map.first().getOrThrow())
|
||||
return Simplification(this, simplification.to)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,10 +107,11 @@ open class Add(private val expr1: Expression, private val expr2: Expression) :
|
|||
*/
|
||||
open class Subtract(private val expr1: Expression, private val expr2: Expression) :
|
||||
ArithmeticOperator(Atom("-"), expr1, expr2) {
|
||||
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
|
||||
override fun simplify(subs: Substitutions): Simplification {
|
||||
val result = Variable("Result")
|
||||
val map = plus(expr2, result, expr1, subs)
|
||||
return result.evaluate(map.first().getOrThrow())
|
||||
val simplification = result.simplify(map.first().getOrThrow())
|
||||
return Simplification(this, simplification.to)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,10 +121,11 @@ open class Subtract(private val expr1: Expression, private val expr2: Expression
|
|||
*/
|
||||
class Multiply(private val expr1: Expression, private val expr2: Expression) :
|
||||
ArithmeticOperator(Atom("*"), expr1, expr2) {
|
||||
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
|
||||
override fun simplify(subs: Substitutions): Simplification {
|
||||
val result = Variable("Result")
|
||||
val map = mul(expr1, expr2, result, subs)
|
||||
return result.evaluate(map.first().getOrThrow())
|
||||
val simplification = result.simplify(map.first().getOrThrow())
|
||||
return Simplification(this, simplification.to)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,20 +137,24 @@ class Multiply(private val expr1: Expression, private val expr2: Expression) :
|
|||
|
||||
class Between(private val expr1: Expression, private val expr2: Expression, private val expr3: Expression) :
|
||||
Operator(Atom("between"), expr1, expr2) {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> {
|
||||
val e1 = expr1.evaluate(subs)
|
||||
val e2 = expr2.evaluate(subs)
|
||||
val e3 = expr3.evaluate(subs)
|
||||
override fun satisfy(subs: Substitutions): Answers {
|
||||
val e1 = expr1.simplify(subs)
|
||||
val e2 = expr2.simplify(subs)
|
||||
val e3 = expr3.simplify(subs)
|
||||
|
||||
require(e1.first is Integer && e2.first is Integer) { "Arguments must be integers" }
|
||||
require(e1.to is Integer && e2.to is Integer) { "Arguments must be integers" }
|
||||
|
||||
val v1 = e1.first as Integer
|
||||
val v2 = e2.first as Integer
|
||||
val v1 = e1.to as Integer
|
||||
val v2 = e2.to as Integer
|
||||
|
||||
return if (variable(e3.first)) {
|
||||
between(v1, v2, e3.first as Variable).map { it + e1.second + e2.second }
|
||||
return if (variable(e3.to, subs)) {
|
||||
between(v1, v2, e3.to as Variable).map { answer ->
|
||||
answer.mapCatching { it + listOfNotNull(e1.mapped, e2.mapped) }
|
||||
}
|
||||
} else {
|
||||
between(v1, v2, e3.first as Integer).map { it + e1.second + e2.second }
|
||||
between(v1, v2, e3.to as Integer).map { answer ->
|
||||
answer.mapCatching { it + listOfNotNull(e1.mapped, e2.mapped) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package prolog.builtins
|
||||
|
||||
import prolog.Answers
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.logic.LogicOperand
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.terms.Body
|
||||
import prolog.ast.terms.Goal
|
||||
import prolog.ast.logic.LogicOperator
|
||||
import prolog.logic.Substituted
|
||||
|
||||
/**
|
||||
* Always fail.
|
||||
*/
|
||||
object Fail : Atom("fail"), Body {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> = emptySequence()
|
||||
override fun satisfy(subs: Substitutions): Answers = emptySequence()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +24,7 @@ typealias False = Fail
|
|||
* Always succeed.
|
||||
*/
|
||||
object True : Atom("true"), Body {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> = sequenceOf(emptyMap())
|
||||
override fun satisfy(subs: Substitutions): Answers = sequenceOf(Result.success(emptyMap()))
|
||||
}
|
||||
|
||||
// TODO Repeat/0
|
||||
|
@ -34,10 +35,14 @@ object True : Atom("true"), Body {
|
|||
* Conjunction (and). True if both Goal1 and Goal2 are true.
|
||||
*/
|
||||
class Conjunction(private val left: LogicOperand, private val right: LogicOperand) : LogicOperator(Atom(","), left, right) {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> = sequence {
|
||||
left.prove(subs).forEach { left ->
|
||||
right.prove(subs + left).forEach { right ->
|
||||
yield(left + right)
|
||||
override fun satisfy(subs: Substitutions): Answers = sequence {
|
||||
left.satisfy(subs).forEach { leftResult ->
|
||||
leftResult.mapCatching { left ->
|
||||
right.satisfy(subs + left).forEach { rightResult ->
|
||||
rightResult.map { right ->
|
||||
yield(Result.success(left + right))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +53,9 @@ class Conjunction(private val left: LogicOperand, private val right: LogicOperan
|
|||
*/
|
||||
open class Disjunction(private val left: LogicOperand, private val right: LogicOperand) :
|
||||
LogicOperator(Atom(";"), left, right) {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> = sequence {
|
||||
yieldAll(left.prove(subs))
|
||||
yieldAll(right.prove(subs))
|
||||
override fun satisfy(subs: Substitutions): Answers = sequence {
|
||||
yieldAll(left.satisfy(subs))
|
||||
yieldAll(right.satisfy(subs))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,12 +70,12 @@ class Bar(leftOperand: LogicOperand, rightOperand: LogicOperand) : Disjunction(l
|
|||
* True if 'Goal' cannot be proven.
|
||||
*/
|
||||
class Not(private val goal: Goal) : LogicOperator(Atom("\\+"), rightOperand = goal) {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> {
|
||||
override fun satisfy(subs: Substitutions): Answers {
|
||||
// If the goal can be proven, return an empty sequence
|
||||
if (goal.prove(subs).toList().isNotEmpty()) {
|
||||
if (goal.satisfy(subs).toList().isNotEmpty()) {
|
||||
return emptySequence()
|
||||
}
|
||||
// If the goal cannot be proven, return a sequence with an empty map
|
||||
return sequenceOf(emptyMap())
|
||||
return sequenceOf(Result.success(emptyMap()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package prolog.builtins
|
||||
|
||||
import prolog.Answers
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.logic.LogicOperand
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.logic.LogicOperator
|
||||
import prolog.logic.Substituted
|
||||
|
||||
class Query(private val query: LogicOperand) : LogicOperator(Atom("?-"), null, query) {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> = query.prove(subs)
|
||||
override fun satisfy(subs: Substitutions): Answers = query.satisfy(subs)
|
||||
}
|
||||
|
|
|
@ -5,20 +5,21 @@
|
|||
*/
|
||||
package prolog.builtins
|
||||
|
||||
import prolog.Answers
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.terms.Operator
|
||||
import prolog.ast.terms.Term
|
||||
import prolog.logic.Substituted
|
||||
import prolog.logic.applySubstitution
|
||||
import prolog.logic.equivalent
|
||||
|
||||
class Equivalent(private val term1: Term, private val term2: Term) : Operator(Atom("=="), term1, term2) {
|
||||
override fun prove(subs: Substituted): Sequence<Substituted> = sequence {
|
||||
override fun satisfy(subs: Substitutions): Answers = sequence {
|
||||
val t1 = applySubstitution(term1, subs)
|
||||
val t2 = applySubstitution(term2, subs)
|
||||
|
||||
if (equivalent(t1, t2)) {
|
||||
yield(emptyMap())
|
||||
if (equivalent(t1, t2, subs)) {
|
||||
yield(Result.success(emptyMap()))
|
||||
}
|
||||
}
|
||||
}
|
Reference in a new issue