fix: Fixes
This commit is contained in:
parent
a1187238c3
commit
83f65bd683
8 changed files with 65 additions and 29 deletions
|
@ -3,9 +3,7 @@ summer(Start, End, Sum) :-
|
||||||
Start \== End,
|
Start \== End,
|
||||||
Next is Start + 1,
|
Next is Start + 1,
|
||||||
summer(Next, End, Rest),
|
summer(Next, End, Rest),
|
||||||
writeln(rest(Rest)),
|
Sum is Start + Rest.
|
||||||
Sum is Start + Rest,
|
|
||||||
writeln(sum(Sum)).
|
|
||||||
|
|
||||||
my_sum :-
|
my_sum :-
|
||||||
write('Enter start: '),
|
write('Enter start: '),
|
||||||
|
@ -17,6 +15,8 @@ my_sum :-
|
||||||
write(Sum), nl.
|
write(Sum), nl.
|
||||||
|
|
||||||
main :-
|
main :-
|
||||||
summer(1, 5, Sum).
|
Start = 1, End = 9,
|
||||||
|
summer(Start, End, Sum),
|
||||||
|
write('The sum of '), write(Start), write(' to '), write(End), write(' is: '), write(Sum), nl.
|
||||||
|
|
||||||
:- initialization(main).
|
:- initialization(main).
|
||||||
|
|
15
examples/meta/calculator.pl
Normal file
15
examples/meta/calculator.pl
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
accumulator :-
|
||||||
|
Sum = 0,
|
||||||
|
shift(Number),
|
||||||
|
NewSum is Sum + Number,
|
||||||
|
write("Result is: "), writeln(NewSum).
|
||||||
|
|
||||||
|
main :-
|
||||||
|
reset(accumulator, Number, Cont),
|
||||||
|
between(1, 5, Number),
|
||||||
|
forall()
|
||||||
|
call(Cont),
|
||||||
|
writeln("End of calculation").
|
||||||
|
|
||||||
|
:- initialization(main).
|
||||||
|
|
|
@ -3,8 +3,9 @@ package prolog.ast.arithmetic
|
||||||
import prolog.Answers
|
import prolog.Answers
|
||||||
import prolog.Substitutions
|
import prolog.Substitutions
|
||||||
import prolog.ast.logic.LogicOperand
|
import prolog.ast.logic.LogicOperand
|
||||||
|
import prolog.ast.terms.Body
|
||||||
|
|
||||||
data class Integer(override val value: Int) : Number, LogicOperand() {
|
data class Integer(override val value: Int) : Number, Body, LogicOperand() {
|
||||||
// Integers are already evaluated
|
// Integers are already evaluated
|
||||||
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import prolog.ast.Database.Program
|
||||||
import prolog.ast.terms.*
|
import prolog.ast.terms.*
|
||||||
import prolog.builtins.True
|
import prolog.builtins.True
|
||||||
import prolog.flags.AppliedCut
|
import prolog.flags.AppliedCut
|
||||||
|
import prolog.flags.AppliedShift
|
||||||
import prolog.logic.applySubstitution
|
import prolog.logic.applySubstitution
|
||||||
import prolog.logic.numbervars
|
import prolog.logic.numbervars
|
||||||
import prolog.logic.occurs
|
import prolog.logic.occurs
|
||||||
|
@ -27,18 +28,23 @@ abstract class Clause(var head: Head, var body: Body) : Term, Resolvent {
|
||||||
// Only if the body can be proven, the substitutions should be returned.
|
// Only if the body can be proven, the substitutions should be returned.
|
||||||
// Do this in a lazy way.
|
// Do this in a lazy way.
|
||||||
|
|
||||||
|
val simplifiedGoal = applySubstitution(goal, subs)
|
||||||
|
|
||||||
// Since we are only interested in substitutions in the goal (as opposed to the head of this clause),
|
// Since we are only interested in substitutions in the goal (as opposed to the head of this clause),
|
||||||
// we can use variable renaming and filter out the substitutions that are not in the goal.
|
// we can use variable renaming and filter out the substitutions that are not in the goal.
|
||||||
val (headEnd, headRenaming) = numbervars(head, Program.variableRenamingStart, emptyMap())
|
val (headEnd, headRenaming) = numbervars(head, Program.variableRenamingStart, emptyMap())
|
||||||
Program.variableRenamingStart = headEnd
|
val (goalEnd, goalRenaming) = numbervars(simplifiedGoal, headEnd, emptyMap())
|
||||||
|
Program.variableRenamingStart = goalEnd
|
||||||
|
|
||||||
|
val reverseGoalRenaming = goalRenaming.entries.associate { (key, value) -> value to key }
|
||||||
|
|
||||||
val renamedHead = applySubstitution(head, headRenaming)
|
val renamedHead = applySubstitution(head, headRenaming)
|
||||||
val simplifiedGoal = applySubstitution(goal, subs)
|
val renamedGoal = applySubstitution(simplifiedGoal, goalRenaming)
|
||||||
unifyLazy(simplifiedGoal, renamedHead, emptyMap()).forEach { headAnswer ->
|
unifyLazy(renamedGoal, renamedHead, emptyMap()).forEach { headAnswer ->
|
||||||
headAnswer.map { headAndGoalSubs ->
|
headAnswer.map { headAndGoalSubs ->
|
||||||
// Filter the substitutions to only include those that map from head to goal
|
// Filter the substitutions to only include those that map from head to goal
|
||||||
val headToGoalSubs = headAndGoalSubs.filterKeys { it in headRenaming.values }
|
val headToGoalSubs = headAndGoalSubs.filterKeys { it in headRenaming.values }
|
||||||
val goalToHeadSubs = headAndGoalSubs.filterKeys { occurs(it as Variable, simplifiedGoal) }
|
val goalToHeadSubs = headAndGoalSubs.filterKeys { occurs(it as Variable, renamedGoal) }
|
||||||
val headResult = headToGoalSubs.filterKeys { key ->
|
val headResult = headToGoalSubs.filterKeys { key ->
|
||||||
goalToHeadSubs.any { occurs(key as Variable, it.value) }
|
goalToHeadSubs.any { occurs(key as Variable, it.value) }
|
||||||
}
|
}
|
||||||
|
@ -47,25 +53,35 @@ abstract class Clause(var head: Head, var body: Body) : Term, Resolvent {
|
||||||
bodyAnswer.fold(
|
bodyAnswer.fold(
|
||||||
onSuccess = { bodySubs ->
|
onSuccess = { bodySubs ->
|
||||||
// If the body can be proven, yield the (combined) substitutions
|
// If the body can be proven, yield the (combined) substitutions
|
||||||
val goalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
|
val renamedGoalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
|
||||||
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, simplifiedGoal) }
|
val goalResult =
|
||||||
|
renamedGoalResult.mapKeys { applySubstitution(it.key, reverseGoalRenaming) }
|
||||||
|
val renamedBodyResult = bodySubs.filterKeys { occurs(it as Variable, renamedGoal) }
|
||||||
|
val bodyResult = renamedBodyResult.mapKeys { applySubstitution(it.key, reverseGoalRenaming) }
|
||||||
yield(Result.success(goalResult + headResult + bodyResult))
|
yield(Result.success(goalResult + headResult + bodyResult))
|
||||||
},
|
},
|
||||||
onFailure = { error ->
|
onFailure = { error ->
|
||||||
if (error is AppliedCut) {
|
when (error) {
|
||||||
|
is AppliedCut -> {
|
||||||
// Find single solution and return immediately
|
// Find single solution and return immediately
|
||||||
if (error.subs != null) {
|
if (error.subs != null) {
|
||||||
val bodySubs = error.subs
|
val bodySubs = error.subs
|
||||||
val goalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
|
val goalResult =
|
||||||
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, simplifiedGoal) }
|
goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
|
||||||
|
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, renamedGoal) }
|
||||||
yield(Result.failure(AppliedCut(goalResult + headResult + bodyResult)))
|
yield(Result.failure(AppliedCut(goalResult + headResult + bodyResult)))
|
||||||
} else {
|
} else {
|
||||||
yield(Result.failure(AppliedCut()))
|
yield(Result.failure(AppliedCut()))
|
||||||
}
|
}
|
||||||
return@sequence
|
return@sequence
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
is AppliedShift -> {
|
||||||
yield(Result.failure(error))
|
yield(Result.failure(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else -> yield(Result.failure(error))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package prolog.ast.terms
|
package prolog.ast.terms
|
||||||
|
|
||||||
|
import prolog.Substitutions
|
||||||
import prolog.ast.logic.Satisfiable
|
import prolog.ast.logic.Satisfiable
|
||||||
|
|
||||||
interface Body : Term, Satisfiable
|
interface Body : Term, Satisfiable {
|
||||||
|
override fun applySubstitution(subs: Substitutions): Body
|
||||||
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ open class Conjunction(val left: LogicOperand, private val right: LogicOperand)
|
||||||
right.fold(
|
right.fold(
|
||||||
// If the right part succeeds, yield the result with the left substitutions
|
// If the right part succeeds, yield the result with the left substitutions
|
||||||
onSuccess = { rightSubs ->
|
onSuccess = { rightSubs ->
|
||||||
yield(Result.success(leftSubs + rightSubs))
|
yield(Result.success(rightSubs + leftSubs))
|
||||||
},
|
},
|
||||||
onFailure = { exception ->
|
onFailure = { exception ->
|
||||||
// If the right part fails, check if it's a cut
|
// If the right part fails, check if it's a cut
|
||||||
|
@ -74,8 +74,8 @@ open class Conjunction(val left: LogicOperand, private val right: LogicOperand)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findNextCutSolution(appliedCut: AppliedCut): Answers = sequence {
|
fun findNextCutSolution(appliedCut: AppliedCut): Answers = sequence {
|
||||||
val leftSubs = appliedCut.subs
|
val leftSubs = appliedCut.subs ?: emptyMap()
|
||||||
right.satisfy(subs + (appliedCut.subs!!)).firstOrNull()?.map { rightSubs ->
|
right.satisfy(subs + leftSubs).firstOrNull()?.map { rightSubs ->
|
||||||
// If the right part succeeds, yield the result with the left substitutions
|
// If the right part succeeds, yield the result with the left substitutions
|
||||||
yield(Result.success(leftSubs + rightSubs))
|
yield(Result.success(leftSubs + rightSubs))
|
||||||
return@sequence
|
return@sequence
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Reset(private val goal: Goal, private val ball: Term, private val cont: Te
|
||||||
if (failure is AppliedShift) {
|
if (failure is AppliedShift) {
|
||||||
require(failure.cont != null) { "Shift must have a continuation" }
|
require(failure.cont != null) { "Shift must have a continuation" }
|
||||||
// Reset/3 succeeds immediately, binding Term1 to Term2 and Cont to the remainder of Goal.
|
// Reset/3 succeeds immediately, binding Term1 to Term2 and Cont to the remainder of Goal.
|
||||||
val shiftSubs = failure.subs
|
val shiftSubs = failure.subs + subs
|
||||||
val appliedBall = applySubstitution(failure.ball, shiftSubs)
|
val appliedBall = applySubstitution(failure.ball, shiftSubs)
|
||||||
val appliedCont = applySubstitution(failure.cont, shiftSubs)
|
val appliedCont = applySubstitution(failure.cont, shiftSubs)
|
||||||
Conjunction(Unify(ball, appliedBall), Unify(appliedCont, cont))
|
Conjunction(Unify(ball, appliedBall), Unify(appliedCont, cont))
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Examples {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun debugHelper() {
|
fun debugHelper() {
|
||||||
loader.load("examples/meta/continuations.pl")
|
loader.load("examples/meta/mib_voorbeelden.pl")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
|
@ -60,6 +60,7 @@ class Examples {
|
||||||
Arguments.of("forall.pl", "Only alice likes pizza.\n"),
|
Arguments.of("forall.pl", "Only alice likes pizza.\n"),
|
||||||
Arguments.of("fraternity.pl", "Citizen robespierre is eligible for the event.\nCitizen danton is eligible for the event.\nCitizen camus is eligible for the event.\n"),
|
Arguments.of("fraternity.pl", "Citizen robespierre is eligible for the event.\nCitizen danton is eligible for the event.\nCitizen camus is eligible for the event.\n"),
|
||||||
Arguments.of("liberty.pl", "Give me Liberty, or give me Death!\nI disapprove of what you say, but I will defend to the death your right to say it.\nThe revolution devours its own children.\nSo this is how liberty dies, with thunderous applause.\n"),
|
Arguments.of("liberty.pl", "Give me Liberty, or give me Death!\nI disapprove of what you say, but I will defend to the death your right to say it.\nThe revolution devours its own children.\nSo this is how liberty dies, with thunderous applause.\n"),
|
||||||
|
Arguments.of("summer.pl", "The sum of 1 to 9 is: 36\n"),
|
||||||
Arguments.of("unification.pl", "While alice got an A, carol got an A, but bob did not get an A, dave did not get an A, unfortunately.\n"),
|
Arguments.of("unification.pl", "While alice got an A, carol got an A, but bob did not get an A, dave did not get an A, unfortunately.\n"),
|
||||||
Arguments.of("write.pl", "gpl zegt: dag(wereld)\n"),
|
Arguments.of("write.pl", "gpl zegt: dag(wereld)\n"),
|
||||||
)
|
)
|
||||||
|
|
Reference in a new issue