tail recursion sum, power, gcd in prolog? - recursion

how can I accomplish this:
Give a tail-recursive definition for each of the following predicates.
power(X,Y,Z): XY=Z.
gcd(X,Y,Z): The greatest common divisor of X and Y is Z.
sum(L,Sum): Sum is the sum of the elements in L.
so far I have done this but not sure if that's correct
power(_,0,1) :- !.
power(X,Y,Z) :- Y1 is Y - 1,power(X,Y1,Z1),Z is X * Z1.
sum(void,0).
sum(t(V,L,R),S) :- sum(L,S1),sum(R,S2), S is V + S1 + S2.

These are not tail recursive. You can write tail recursive variants by using an accumulator, see this answer.
Your sum is over a tree, which is unusual, normally one would use a list. In Prolog [] is the empty list and [X|R] is the pattern for a nonempty list with the head X and the tail R.

Related

Prolog: Check predicate against every item in the list

Basically, I want to be able to check to see if at least one value in a list satisfies some predicate.
What I have so far:
need(x,y).
check_list(X,[H|T]) :-
need(H,X).
And so this works fine so long as I only have one value in the list. I'm not sure how to make it check the other values. When I try and use recursion I eventually find an element that satisfies the second predicate but it then goes back up the stack which will eventually cause it to be false.How can I make it 'break' essentially?
The backtracking you are seeing during recursion is Prolog attempting to find more ways for the predicate to succeed. This is a fundamental Prolog behavior and is what makes it useful. It seeks to find all of the solutions.
In your case, you only want to confirm one solution to the problem of, An element in the list that meets a specific criterion. For this, you could use a cut:
check_list(X, [H|_]) :-
need(X, H), !. % Don't backtrack after success
check_list(X, [_|T]) :-
check_list(X, T).
Or you could use once/1 which is specifically designed to handle cases where you only want a single solution:
check_list(X, [H|_]) :-
need(X, H).
check_list(X, [_|T]) :-
check_list(X, T).
check_list_once(X, L) :- once(check_list(X, L)).
Here is an example of what you can do.
I want to check is numbers are odd.
is_even(X) :-
X mod 2 =:= 0.
check_list(L, CL) :-
include(is_even, L, CL).
with result
?- check_list([1,2,3,4,5], L).
L = [2, 4].
?- check_list([1,3,5], L).
L = [].
You can use simple recursion:
need(x,y).
check_list(X,[H|T]) :-
( need(H,X) -> true;
check_list(X,T) ).
You can see in the examples below that this definition is deterministic:
?- check_list(y,[1,2,3]).
false.
?- check_list(y,[x,2,3]).
true.
?- check_list(y,[1,2,x]).
true.
?- check_list(Y,[1,2,x]).
Y = y.
?- check_list(Y,[1,2,3]).
false.
?- check_list(Y,[1,x,3]).
Y = y.
?- check_list(Y,[1,X,3]).
Y = y,
X = x.
?- check_list(Y,[1,2,3]), Y = x.
false.
?- check_list(Y,[1,2,3]), Y = y.
false.
?- check_list(Y,[1,2,3]).
false.
?- check_list(Y,[1,2,x]), Y = y.
Y = y.
Though if you want your queries to have uninstantiated variables e.g check_list(Y,[1,2,x]). and you add another fact need(x,z). Then:
?- check_list(Y,[1,2,x]).
Y = y.
Returns only one result and not Y = z. You could use if_/3 from library reif if you want a better definition of check_list/3.

SMLNJ powerset function

I am trying to print the size of a list created from below power set function
fun add x ys = x :: ys;
fun powerset ([]) = [[]]
| powerset (x::xr) = powerset xr # map (add x) (powerset xr) ;
val it = [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]] : int list list;
I have the list size function
fun size xs = (foldr op+ 0 o map (fn x => 1)) xs;
I couldnt able to merge these two functions and get the result like
I need something like this:
[(0,[]),(1,[3]),(1,[2]),(2,[2,3]),(1,[1]),(2,[1,3]),(2,[1,2]),(3,[1,2,3])]
Could anyone please help me with this?
You can get the length of a list using the built-in List.length.
You seem to forget to mention that you have the constraint that you can only use higher-order functions. (I am guessing you have this constraint because others these days are asking how to write powerset functions with this constraint, and using foldr to count, like you do, seems a little constructed.)
Your example indicates that you are trying to count each list in a list of lists, and not just the length of one list. For that you'd want to map the counting function across your list of lists. But that'd just give you a list of lengths, and your desired output seems to be a list of tuples containing both the length and the actual list.
Here are some hints:
You might as well use foldl rather than foldr since addition is associative.
You don't need to first map (fn x => 1) - this adds an unnecessary iteration of the list. You're probably doing this because folding seems complicated and you only just managed to write foldr op+ 0. This is symptomatic of not having understood the first argument of fold.
Try, instead of op+, to write the fold expression using an anonymous function:
fun size L = foldl (fn (x, acc) => ...) 0 L
Compare this to op+ which, if written like an anonymous function, would look like:
fn (x, y) => x + y
Folding with op+ carries some very implicit uses of the + operator: You want to discard one operand (since not its value but its presence counts) and use the other one as an accumulating variable (which is better understood by calling it acc rather than y).
If you're unsure what I mean about accumulating variable, consider this recursive version of size:
fun size L =
let fun sizeHelper ([], acc) = acc
| sizeHelper (x::xs, acc) = sizeHelper (xs, 1+acc)
in sizeHelper (L, 0) end
Its helper function has an extra argument for carrying a result through recursive calls. This makes the function tail-recursive, and folding is one generalisation of this technique; the second argument to fold's helper function (given as an argument) is the accumulating variable. (The first argument to fold's helper function is a single argument rather than a list, unlike the explicitly recursive version of size above.)
Given your size function (aka List.length), you're only a third of the way, since
size [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]]
gives you 8 and not [(0,[]),(1,[3]),(1,[2]),(2,[2,3]),...)]
So you need to write another function that (a) applies size to each element, which would give you [0,1,1,2,...], and (b) somehow combine that with the input list [[],[3],[2],[2,3],...]. You could do that either in two steps using zip/map, or in one step using only foldr.
Try and write a foldr expression that does nothing to an input list L:
foldr (fn (x, acc) => ...) [] L
(Like with op+, doing op:: instead of writing an anonymous function would be cheating.)
Then think of each x as a list.

Permutation predicate in Prolog

I have written the following in Prolog (I am using version 7.4.0-rc1), trying to define a predicate insertPermutation/2 which is true if and only if both arguments are lists, one a permutation of the other.
delete(X,[X|T],T). % Base case, element equals head.
delete(X,[A|B],[A|C]) :- delete(X,B,C). % And/or repeat for the tail.
insert(X,Y,Z) :- delete(X,Z,Y). % Inserting is deletion in reverse.
insertPermutation([],[]). % Base case.
insertPermutation([H|T],P) :- insertPermutation(Q,T), insert(H,Q,P). % P permutation of T, H inserted.
I have already been made aware that delete is not a good name for the above helper predicate. We are required to write these predicates, and we cannot use the built-in predicates. This is why I wrote the above code in this way, and I chose the name I did (because I first wrote it to delete an element). It is true if and only if the third argument is a list, equal to the list in the second argument with the first instance of the first argument removed.
The insertPermutation predicate recursively tests if P equals a permutation of the tail of the first list, with the head added in any position in the permutation. This way it works to the base case of both being empty lists.
However, the permutation predicate does not behave the way I want it to. For instance, to the query
?- insertPermutation([1,2,2],[1,2,3]).
Prolog does not return false, but freezes. To the query
?- insertPermutation(X,[a,b,c]).
Prolog responds with
X = [a, b, c] ;
X = [b, a, c] ;
X = [c, a, b] ;
X = [a, c, b] ;
X = [b, c, a] ;
X = [c, b, a] ;
after which it freezes again. I see these problems are related, but not how. Can someone point out what case I am missing?
Edit: Two things, this is homework, and I need to solve this problem using an insert predicate. I wrote this one.
The answer is to change the last line
% P permutation of T, H inserted.
insertPermutation([H|T],P) :-
insertPermutation(Q,T),
insert(H,Q,P).
% P permutation of T, H inserted.
insertPermutation(P,[H|T]) :-
insertPermutation(Q,T),
insert(H,Q,P).
The use cases only needed to check if the first element is a permutation of the latter, not the other way around (or vice versa). Anti-climatic, but the answer to my problem.

New to SML / NJ. Making a custom insert function

Define a function that, given a list L, an object x, and a positive
integer k, returns a copy of L with x inserted at the k-th position.
For example, if L is [a1, a2, a3] and k=2, then [a1, x, a2, a3] is
returned. If the length of L is less than k, insert at the end. For
this kind of problems, you are supposed not to use, for example, the
length function. Think about how the function computes the length. No
'if-then-else' or any auxiliary function.
I've figured out how to make a function to find the length of a list
fun mylength ([]) = 0
| mylength (x::xs) = 1+ mylength(xs)
But, as the questions states, I can't use this as an auxiliary function in the insert function. Also, i'm lost as to how to go about the insert function? Any help or guidance would be appreciated!
Here's how to do this. Each recursive call you pass to the function tail of the list and (k - 1) - position of the new element in the tail of the list. When the list is empty, you construct a single-element list (which was given to you); when k is 0, you append your element to what's left from the list. On the way back, you append all heads of the list that you unwrapped before.
fun kinsert [] x k = [x]
| kinsert ls x 0 = x::ls
| kinsert (l::ls) x k = l::(kinsert ls x (k - 1))
I used a 0-indexed list; if you want 1-indexed, just replace 0 with 1.
As you can see, it's almost the same as your mylength function. The difference is that there are two base cases for recursion and your operation on the way back is not +, but ::.
Edit
You can call it like this
kinsert [1,2,3,4,5,6] 10 3;
It has 3 arguments; unlike your length function, it does not wrap arguments in a tuple.
Here's how I'd approach it. The following assumes that the list item starts from zero.
fun mylength (lst,obj,pos) =
case (lst,obj,pos) of
([],ob,po)=>[ob]
| (xs::ys,ob,0) => ob::lst
| (xs::ys,ob,po) => xs::mylength(ys,obj,pos-1)

Canonical way to get a more specific lemma

Say I have a lemma mylem: foo ?a = bar ?a, and I need to apply it on a goal that has two occurrences of foo, e.g. baz (foo (f p q)) (foo (g r s)), but only at one of these positions. I know of two ways of doing that without having to write out all of p,q..., which can be complex expressions.
Using apply (subst mylem) followed by an appropriate number (here, zero or one) of back commands.
Using apply (subst mylem[where a = 'foo x y', standard]), where x and y are unbound names.
The use of subst here is just for demonstration; I really do want to modify the lemma, e.g. to use it with rule when there are multiple possible matches that I’d like to disambiguate this way.
Both approaches look like bad style to me. Is there a nicer way of achieving that?
You can tell subst which occurrence it should replace: subst (i) mylem unfolds mylem at the i-th matching occurrence. This saves you the back steps. You can also list multiple positions as in subst (1 2) mylem. If you want to unfold mylem in premises, use subst (asm) (1 2) mylem.
In general, I do not know a way to achieve what you want inside an apply script. On the theory level, you can use lemmas with the for clause to generalise over locally introduced variables:
lemmas mylem' = mylem[where a="f x y"] for x y
Inside a structured proof, you can do it explicitly like this:
{ fix x y note mylem[where a="f x y"] }
note mylem' = this

Resources