fix: Fixes

This commit is contained in:
Tibo De Peuter 2025-05-18 14:56:16 +02:00
parent a1187238c3
commit 83f65bd683
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
8 changed files with 65 additions and 29 deletions

View file

@ -3,9 +3,7 @@ summer(Start, End, Sum) :-
Start \== End,
Next is Start + 1,
summer(Next, End, Rest),
writeln(rest(Rest)),
Sum is Start + Rest,
writeln(sum(Sum)).
Sum is Start + Rest.
my_sum :-
write('Enter start: '),
@ -17,6 +15,8 @@ my_sum :-
write(Sum), nl.
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).

View 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).

View file

@ -3,8 +3,9 @@ package prolog.ast.arithmetic
import prolog.Answers
import prolog.Substitutions
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
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)

View file

@ -6,6 +6,7 @@ import prolog.ast.Database.Program
import prolog.ast.terms.*
import prolog.builtins.True
import prolog.flags.AppliedCut
import prolog.flags.AppliedShift
import prolog.logic.applySubstitution
import prolog.logic.numbervars
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.
// 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),
// we can use variable renaming and filter out the substitutions that are not in the goal.
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 simplifiedGoal = applySubstitution(goal, subs)
unifyLazy(simplifiedGoal, renamedHead, emptyMap()).forEach { headAnswer ->
val renamedGoal = applySubstitution(simplifiedGoal, goalRenaming)
unifyLazy(renamedGoal, renamedHead, emptyMap()).forEach { headAnswer ->
headAnswer.map { headAndGoalSubs ->
// Filter the substitutions to only include those that map from head to goal
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 ->
goalToHeadSubs.any { occurs(key as Variable, it.value) }
}
@ -47,24 +53,34 @@ abstract class Clause(var head: Head, var body: Body) : Term, Resolvent {
bodyAnswer.fold(
onSuccess = { bodySubs ->
// If the body can be proven, yield the (combined) substitutions
val goalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, simplifiedGoal) }
val renamedGoalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
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))
},
onFailure = { error ->
if (error is AppliedCut) {
// Find single solution and return immediately
if (error.subs != null) {
val bodySubs = error.subs
val goalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, simplifiedGoal) }
yield(Result.failure(AppliedCut(goalResult + headResult + bodyResult)))
} else {
yield(Result.failure(AppliedCut()))
when (error) {
is AppliedCut -> {
// Find single solution and return immediately
if (error.subs != null) {
val bodySubs = error.subs
val goalResult =
goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, renamedGoal) }
yield(Result.failure(AppliedCut(goalResult + headResult + bodyResult)))
} else {
yield(Result.failure(AppliedCut()))
}
return@sequence
}
return@sequence
} else {
yield(Result.failure(error))
is AppliedShift -> {
yield(Result.failure(error))
}
else -> yield(Result.failure(error))
}
}
)

View file

@ -1,5 +1,8 @@
package prolog.ast.terms
import prolog.Substitutions
import prolog.ast.logic.Satisfiable
interface Body : Term, Satisfiable
interface Body : Term, Satisfiable {
override fun applySubstitution(subs: Substitutions): Body
}

View file

@ -55,7 +55,7 @@ open class Conjunction(val left: LogicOperand, private val right: LogicOperand)
right.fold(
// If the right part succeeds, yield the result with the left substitutions
onSuccess = { rightSubs ->
yield(Result.success(leftSubs + rightSubs))
yield(Result.success(rightSubs + leftSubs))
},
onFailure = { exception ->
// 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 {
val leftSubs = appliedCut.subs
right.satisfy(subs + (appliedCut.subs!!)).firstOrNull()?.map { rightSubs ->
val leftSubs = appliedCut.subs ?: emptyMap()
right.satisfy(subs + leftSubs).firstOrNull()?.map { rightSubs ->
// If the right part succeeds, yield the result with the left substitutions
yield(Result.success(leftSubs + rightSubs))
return@sequence

View file

@ -39,7 +39,7 @@ class Reset(private val goal: Goal, private val ball: Term, private val cont: Te
if (failure is AppliedShift) {
require(failure.cont != null) { "Shift must have a continuation" }
// 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 appliedCont = applySubstitution(failure.cont, shiftSubs)
Conjunction(Unify(ball, appliedBall), Unify(appliedCont, cont))

View file

@ -27,7 +27,7 @@ class Examples {
@Test
fun debugHelper() {
loader.load("examples/meta/continuations.pl")
loader.load("examples/meta/mib_voorbeelden.pl")
}
@ParameterizedTest
@ -60,6 +60,7 @@ class Examples {
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("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("write.pl", "gpl zegt: dag(wereld)\n"),
)