Prolog recursion overflow - recursion

fact(1,1):-!.
fact(N,F):-
N1=N-1,
fact(N1,F1),
F=F1*N.
It leads to the stackoverflow(not the site)! It shouldn't because of the cut(!). Does it work in SWI-Prolog?

Please note that both definitions (the OP's and pad's) do not terminate for a query like fact(0,N). But also fact(1,2) does not terminate. It should fail. And for fact(N, F) it gives only one correct answer, but there should be infinitely many. Using cuts for such purpose is very tricky. The cleanest way to fix this is to add the goal N > 0 to the rule and have a fact fact(0,1). There is an even better way, provided you use SWI-Prolog: Use library(clpfd). In the documentation, you find n_factorial/2 already defined. It can be used for queries like:
?- n_factorial(47, F).
F = 258623241511168180642964355153611979969197632389120000000000
; false.
?- n_factorial(N, 1).
N = 0
; N = 1
; false.
?- n_factorial(N, 3).
false.

Related

Idris impossible keyword proves a wrong proposition

data Even: Nat -> Type where
EvenZ: Even Z
EvenS: Even n -> Even (n + 2)
total
lemma1: Even Z
lemma1 = EvenZ
-- total
-- lemma2: Even Z
-- lemma2 impossible -- Idris says 'lemma2 is a valid case' and I agree with you
total
lemma3: Even 2
lemma3 = EvenS EvenZ
total
lemma4: Even 2 -> Void
lemma4 x impossible -- what does it work?
total
lemma5: Even 1 -> Void
lemma5 x impossible
I wrote some proofs on Even.
lemma1, lemma2 and lemma3 are ok, but lemma4 looks strange to me.
AFAIK, both lemma3 and lemma4 can not be provable at the same time.
I expected impossible keyword in lemma4 not to work and expected Idris to show me some error messages about the wrong usage of impossible.
Is impossible an unsafe keyword that can be used to assert to type checker?

Mirror binary tree in Prolog

What I have...
tree(nil).
tree(b(Left,_,Right)) :-
tree(Left),
tree(Right).
mirror(b(Left,Head,Right), NewTree) :-
mirror(Left,NewLeft),
mirror(Right,NewRight),
NewTree = b(NewRight,Head,NewLeft).
What I'm querying...
mirror(b(nil,a,b(nil,b,nil)), Result).
Expected result
Result = b(b(nil,b,nil),a,nil).
The tree b(Left,Right,Head) is the first argument of mirror, NewTree is the goal. mirror(Left,NewLeft) recurses through the left side and yields the goal NewLeft, same for Right. NewTree is the tree b(NewRight,Head,NewLeft).
I'm not sure why this isn't working could someone please help.
Based on your current code
tree(nil).
tree(b(Left,_,Right)) :-
tree(Left),
tree(Right).
mirror(b(Left,Head,Right), NewTree) :-
mirror(Left,NewLeft),
mirror(Right,NewRight),
NewTree = b(NewRight,Head,NewLeft).
you are very close.
As noted in a comment by Steven
You're missing the base case for mirror/2. What should NewTree be when the input tree is nil?
is very helpful.
Before getting to the full working predicate lets clear up a other things.
The predicate for tree is not needed.
tree(nil).
tree(b(Left,_,Right)) :-
tree(Left),
tree(Right).
I don't know if you are showing this to shows us that you know how a tree works or what but for others reading this predicate it is not needed for the answer.
That leaves only
mirror(b(Left,Head,Right), NewTree) :-
mirror(Left,NewLeft),
mirror(Right,NewRight),
NewTree = b(NewRight,Head,NewLeft).
A standard style with using a variable that works like an input and output with several usages is for the starting one, append a 0, then for each succeeding use increase the appended number and for the result append nothing.
mirror(b(Left0,Head,Right0), NewTree) :-
mirror(Left0,Left),
mirror(Right0,Right),
NewTree = b(Right,Head,Left).
Next =/2 is just doing unification. This can be refactored as such
mirror(b(Left0,Head,Right0), b(Right,Head,Left)) :-
mirror(Left0,Left),
mirror(Right0,Right).
Now back to your problem
Since a tree is a recursive structure, it can be processed with with recursion. Predicates that work on recursive data structures need a base clause and a clause to do the recursion. You already have a clause to do the recursion but just need a base clause.
If you use the SWI-Prolog gui tracer on your code for the query
mirror(b(nil,a,b(nil,b,nil)), Result).
you will see
that when one of the branches is just nil there is no mirror/2 rule to handle this case.
Adding
mirror(nil,nil).
will solve your problem.
?- mirror(b(nil,a,b(nil,b,nil)), Result).
Result = b(b(nil, b, nil), a, nil).
The entire predicate.
mirror(nil,nil).
mirror(b(Left0,Head,Right0), b(Right,Head,Left)) :-
mirror(Left0,Left),
mirror(Right0,Right).

Prolog, issues with base case failing

I'm currently writing a prolog A* search function, and ran into an issue with one of my queries. So I decided to manually test the base case, as that's where the trace was failing.
addAChild([Child],[],[Child]):-
write(woo empty).
I manually ran:
addAChild([c(1,1,p(1,2)),[]],[],A).
but it just fails.
Any help would be appreciated.
[Child] (a 1-element list) cannot unify with [c(1,1,p(1,2)),[]] (a 2-elements list).
That's why it is failing.
You can manually test in the interactive interpreter that those two terms fail to unify:
?- addAChild([Child],[],[Child]) = addAChild([c(1,1,p(1,2)),[]],[],A).
false.
and then you can inspect recursively which part is failing.
The term name (addAChild) and the arity (3) is the same, so we can rule off this issue.
Then proceed to unify each argument:
?- [Child] = A.
A = [Child].
?- [] = [].
true.
?- [Child] = [c(1,1,p(1,2)),[]].
false.

Tell if number is odd or even with SML

This is the second SML program I have been working on. These functions are mutually recursive. If I call odd(1) I should get true and even(1) I should get false. These functions should work for all positive integers. However, when I run this program:
fun
odd (n) = if n=0 then false else even (n-1);
and
even (n) = if n=0 then true else odd (n-1);
I get:
[opening test.sml]
test.sml:2.35-2.39 Error: unbound variable or constructor: even
val it = () : unit
How can I fix this?
The problem is the semicolon (;) in the middle. Semicolons are allowed (optionally) at the end of a complete declaration, but right before and is not the end of a declaration!
So the compiler is blowing up on the invalid declaration fun odd (n) = if n=0 then false else even (n-1) that refers to undeclared even. If it were to proceed, it would next blow up on the illegal occurrence of and at the start of a declaration.
Note that there are only two situations where a semicolon is meaningful:
the notation (...A... ; ...B... ; ...C...) means "evaluate ...A..., ...B..., and ...C..., and return the result of ...C....
likewise the notation let ... in ...A... ; ...B... ; ...C... end, where the parentheses are optional because the in ... end does an adequate job bracketing their contents.
if you're using the interactive REPL (read-evaluate-print loop), a semicolon at the end of a top-level declaration means "OK, now actually go ahead and elaborate/evaluate/etc. everything so far".
Idiomatic Standard ML doesn't really use semicolons outside of the above situations; but it's OK to do so, as long as you don't start thinking in terms of procedural languages and expecting the semicolons to "terminate statements", or anything like that. There's obviously a relationship between the use of ; in Standard ML and the use of ; in languages such as C and its syntactic descendants, but it's not a direct one.
I'm sure there's a didactic point in making these functions recursive, but here's some shorter ones:
fun even x = x mod 2 = 0
val odd = not o even

issues regarding prolog backtracking to find other solution

I am beginner of Prolog.
what I have is a function traverse a list and return true when it satisfies the condition.
for example, check_version checks if the package version met the condition(eg. the version satisfies the condition such as greater than or less than the specific version) and check_all checks takes a list of versions and conditions to check one by one.
package('python', '2.6.5').
package('python', '2.5.4').
package('python', '1.5.2').
package('python', '3.1.0').
check_version(Pac, Ver, Cmp, V):-
package(Pac, V),
cmp_version(V, Ver, Cmp).
check_all( Pac, [], [], V):-
package(Pac, V).
check_all(Pac, [Ver], [Cmp], V):-
check_version(Pac, Ver, Cmp, V).
check_all(Pac, [Ver|VerS], [Cmp|CmpS], V):-
check_version(Pac, Ver, Cmp, V),
check_all(Pac, VerS, CmpS, V).
The problem I have is when try to find other solutions, it gives me duplicate solution.
I get:
check_all('python', ['3.0','2.4'], [lt,ge], V).
V = '2.6.5' ;
V = '2.6.5' ;
V = '2.5.4' ;
V = '2.5.4' .
expected:
check_all('python', ['3.0','2.4'], [lt,ge], V).
V = '2.6.5' ;
V = '2.5.4' .
I used trace to track it, and the problem I found, when it try to find another solution it back tracks and will return fail until find the right solution. Like the example above, apparently, it will return true for V='2.6.5' at first and take that to back track and run the functions, and we expect it returns false and then when it reach the beginning it run package('python', V) and V will take another value.
...
Exit: (7) check_all(python, ['3.0', '2.4'], [lt, ge], '2.6.5') ? creep
V = '2.6.5'
...
Fail: (9) check_version(python, '2.4', ge, '2.6.5') ? creep
Redo: (8) check_all(python, ['2.4'], [ge], '2.6.5') ? creep
Call: (9) check_version(python, '2.4', ge, '2.6.5') ? creep
Call: (10) package(python, '2.6.5') ? creep
Exit: (10) package(python, '2.6.5') ? creep
when back tracking, in check_all, it fails at check_all as we expected, but it returns true when it backtracks check_version and run package(python, '2.6.5') as V=2.6.5 a new value. so it return true again when V=2.6.5. is there any way to solve this problem?
To localize your problem, first reduce the size of your input. A single element suffices:
?- check_all('python', ['3.0'], [lt], V).
Now, which rules apply for a single element?
Both rules apply! So remove the more specialized one.
There is also another way how to localize such a problem. Simply compare the rules to each other and try to figure out a case where they both apply. The last rule applies for VerS = [] when also the first applies.
Applying a predicate to each element of a list is best done by a predicate that has the list as its first argument. Without going into detail, this makes the predicate succeed when the iteration is complete, if the argument is a list and not a variable (i.e. when it is an input argument). You should have two clauses: one to deal with the empty list and one for the general case:
foo([]). % succeed
foo([X|Xs]) :-
/* apply a predicate to X */
foo(Xs). % apply predicate to the rest of the list
An important thing here is that you don't need a third clause that deals with lists with one element only, since a list with one element is actually a list with an element and an empty list as its tail:
?- [a] == [a|[]].
true.
?- [a] = [a|[]].
true.
Another important thing is that there is nothing you should be doing in the base case, empty list (at least for your example).
To the problem now: your inputs are
the package name
two lists holding pairs of arguments to a predicate you have defined elsewhere (cmp_version/3). This is your list of conditions.
Implementation:
Known packages are available as facts: they can be enumerated by backtracking.
Conditions are an input arguments, provided as a list: you need to apply the condition to each element of the list(s).
The predicate:
check_all([], [], _, _).
check_all([V|Vs], [C|Cs], Name, Version) :-
package(Name, V), % enumerate all known packages by backtracking
cmp_version(Version, V, Cmp), % condition
check_all(Vs, Cs, Name, Version). % apply condition to the rest of the list(s)
You should read the documentation of maplist. You can express the query for example as:
?- maplist(check_version(python), ['3.0', '2.4'], [lt, ge], Versions).
where you have defined a predicate check_version/4 that looks something like:
check_version(Name, V, Cmp, Version) :-
package(Name, Version),
cmp_version(Version, V, Cmp).
As a side note, maplist will reorder its arguments to make it behave like the explicit iteration above.
EDIT
Naming issues, after #mat's comments: one very useful naming convention is to use a name that has descriptive one-word names for the arguments, delimited by underscores. For example, package/2 becomes package_version/2 since its first argument is the package and the second one the version.

Resources