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

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

View file

@ -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,24 +53,34 @@ 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) {
// Find single solution and return immediately is AppliedCut -> {
if (error.subs != null) { // Find single solution and return immediately
val bodySubs = error.subs if (error.subs != null) {
val goalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) } val bodySubs = error.subs
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, simplifiedGoal) } val goalResult =
yield(Result.failure(AppliedCut(goalResult + headResult + bodyResult))) goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
} else { val bodyResult = bodySubs.filterKeys { occurs(it as Variable, renamedGoal) }
yield(Result.failure(AppliedCut())) yield(Result.failure(AppliedCut(goalResult + headResult + bodyResult)))
} else {
yield(Result.failure(AppliedCut()))
}
return@sequence
} }
return@sequence
} else { is AppliedShift -> {
yield(Result.failure(error)) yield(Result.failure(error))
}
else -> yield(Result.failure(error))
} }
} }
) )

View file

@ -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
}

View file

@ -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

View file

@ -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))

View file

@ -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"),
) )