Related
Is it possible to create a predicate max/2 without an accumulator so that max(List, Max) is true if and only if Max is the maximum value of List (a list of integers)?
Yes, you can calculate the maximum after the recursive step. Like:
max([M],M). % the maximum of a list with one element is that element.
max([H|T],M) :-
max(T,M1), % first calculate the maximum of the tail.
M is max(H,M1). % then calculate the real maximum as the max of
% head an the maximum of the tail.
This predicate will work on floating points for instance. Nevertheless it is better to use an accumulator since most Prolog interpreters use tail call optimization (TCO) and predicates with accumulators tend to work with tail calls. As a result predicates with TCO will usually not get a stack overflow exception if you want to process huge lists.
As #Lurker says, is only works in case that the list is fully grounded: it is a finite list and all elements grounded. You can however use Prolog's constraint logic programming package clp(fd):
:- use_module(library(clpfd)).
max([M],M). % the maximum of a list with one element is that element.
max([H|T],M) :-
max(T,M1), % first calculate the maximum of the tail.
M #= max(H,M1). % then calculate the real maximum as the max of
% head an the maximum of the tail.
You can then for instance call:
?- max([A,B,C],M),A=2,B=3,C=1.
A = 2,
B = M, M = 3,
C = 1 ;
false.
So after the max/2 call, by grounding A, B and C, we obtain M=3.
Neither the standard predicate is/2 nor a CLP(FD) predicate (#=)/2 can do mathematics here. So that in the end, for certain applications such as exact geometry, they might not be suitable.
To make a point lets consider an example and the alternative of a computer algebra system (CAS). I am doing the demonstration with the new Jekejeke Minlog 0.9.2 prototype which provides CAS from within Prolog.
As a preliminary we have two predicates eval_keys/2 and min_key/2, their code is found at the appendix in this post. Lets illustrate what this predicates do, first with integer. The first predicate just makes the keys of a pair list evaluated:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.25-3-gc3a87c2)
Copyright (c) 1990-2016 University of Amsterdam, VU Amsterdam
?- eval_keys([(1+3)-foo,2-bar],L).
L = [4-foo,2-bar]
The second predicate picks this first value where the key is minimum:
?- min_key([4-foo,2-bar],X).
X = bar
Now lets look at other key values, we will use square roots, which belong to the domain of algebraic numbers. Algebraic numbers are irrational and thus never fit into a float. We therefore get for the new example the outcome foo:
?- eval_keys([(sqrt(98428513)+sqrt(101596577))-foo,sqrt(400025090)-bar],L).
L = [20000.62724016424-foo, 20000.627240164245-bar].
?- min_key([20000.62724016424-foo, 20000.627240164245-bar], X).
X = foo.
CLP(FD) has only integers and there is no direct way to represent algebraic numbers. On the other hand many CAS systems support radicals. Our Prototype even supports comparison of them so that we can obtain the exact result bar:
Jekejeke Prolog 2, Runtime Library 1.2.2
(c) 1985-2017, XLOG Technologies GmbH, Switzerland
?- eval_keys([(sqrt(98428513)+sqrt(101596577))-foo,sqrt(400025090)-bar],L).
L = [radical(0,[98428513-1,101596577-1])-foo,
radical(0,[400025090-1])-bar]
?- min_key([radical(0,[98428513-1,101596577-1])-foo,
radical(0,[400025090-1])-bar],X).
X = bar
That bar is the exact result can be seen for example by using a multi-precision calculator. If we double the precision we indeed see that the last square root is the smaler one and not the sum of the square roots:
?- use_module(library(decimal/multi)).
% 7 consults and 0 unloads in 319 ms.
Yes
?- X is mp(sqrt(98428513)+sqrt(101596577), 32).
X = 0d20000.627240164244658958331341095
?- X is mp(sqrt(400025090), 32).
X = 0d20000.627240164244408966171597261
But a CAS need not to proceed this way. For example our Prolog implementation uses a Swinnerton-Dyer polynomial inspired method to compare radical expressions, which works purely symbolic.
Appendix Test Code:
% :- use_module(library(groebner/generic)). /* to enable CAS */
eval_keys([X-A|L], [Y-A|R]) :- Y is X, eval_keys(L, R).
eval_keys([], []).
min_key([X-A|L], B) :- min_key(L, X, A, B).
min_key([X-A|L], Y, _, B) :- X < Y, !, min_key(L, X, A, B).
min_key([_|L], X, A, B) :- min_key(L, X, A, B).
min_key([], _, A, A).
I'm working on a prolog algorithm that will perform a "swap" on a list.
Example:
Input: [1,2,3,4] -> Output: [3,4,1,2]
Input: [1,2,3,4,5] -> Output: [4,5,3,1,2]
The first half and second half of the list swap places, if there is an odd number then the center element retains it's position. I have come up with an algorithm, but I am getting an error:
?- swap([1,2,3,4],L).
ERROR: length/2: Type error: `integer' expected, found `round(4/2)'
My code is as follows:
swap(L, S) :-
length(L, Length),
reverse(L, L2),
mixing(L, Length, A),
trim(L2, Length/2 , B),
append(A,B,S).
trim(L,N,S) :-
length(P,N),
append(P,S,L).
mixing(L, Length, A) :-
( mod(Length, 2) == 0
-> trim(L, round(Length/2), A)
; trim(L, round(Length/2), A)
).
The problem is that in 'mixing' when I call trim (L, round(Length/2), A) the type is not integer? I understand that Length/2 is not an integer (most likely a float) and I thought round was equivalent to integer(expr) which rounds and transforms the data type to an integer. I also tried replacing round with the truncate(expr) and integer(expr), but I was receiving the same errors. Can someone explain what I'm doing wrong?
Prolog doesn't do inline expression evaluation. Thus, calls such as trim(L2, Length/2 , B) and trim(L, round(Length/2), A) will not work as you expect. Expressions are only evaluated in specific when using certain operators such as is/2, arithmetic comparisons, or their CLP(FD) counterparts. These expressions would need to be done as: L is Length // 2, trim(L2, L, B) and R is round(Length/2), trim(L, R, A) if done literally.
Your solution could be condensed, however, as follows.
swap(L, S) :-
same_length(L, S), % L and S are necessarily the same length
length(L, N),
M is N // 2, % integer divide ; half the original list length
length(Left, M), % Left is a list of half the length of L
% or half minus one if the length is odd
( (N mod 2) =:= 1 % If the original length is odd...
-> append(Left, [H|Right], L), % then L is Left + [H|Right]
append(Right, [H|Left], S) % So, S is Right + [H|Left]
; append(Left, Right, L), % otherwise, L is Left + Right
append(Right, Left, S) % So, S is Right + Left
).
round is not a function, it's a predicate. I haven't looked at the rest of the code, but that line should be
round(Length/2, R), trim(L, R, A)
EDIT: BTW, you're overthinking it.
swap([], []).
swap([X], [X]).
swap([X, Y | A], [Y, X | B]) :- swap(A, B).
Here's another solution that is based upon a modification to a predicate posted by #joel76 for splitting a list into two equal length lists. The modification I made enables the predicate to succeed with an odd-length list by including the "middle" list of 0 or 1 elements as an argument. It also uses same_length to constrain the arguments to avoid a termination issue for certain arguments. I included a simple implementation of same_length/2 which not all Prologs have (it is included with SWI Prolog).
swap(L, S) :-
same_length(L, S),
div(L, Front, Middle, Back), % L is divided into two halfs & middle
append(Back, Middle, NewFront), % S is Back + Middle + Front
append(NewFront, Front, S).
% List L consists of Left + Middle + Right where Left and Right are equal length
% and Middle has maximum length of 1
%
div(L, Left, Middle, Right) :-
split(L, L, Left, Middle, Right).
split(L, [], [], [], L).
split([H|T], [_], [], [H], T).
split([H|T], [_, _|T1], [H|T2], M, Right) :-
split(T, T1, T2, M, Right).
% same_length/2 is pre-defined in SWI Prolog and succeeds if the arguments
% are lists of equal length
%
same_length([], []).
same_length([_|Xs], [_|Ys]) :- same_length(Xs, Ys).
an idiomatic solution:
swap(L,S) :-
%maplist(when_, [
append([X,C,Y],L), (C=[];C=[_]), same_length(X,Y),
reverse(X,U), reverse(Y,V), append([U,C,V],S)
%])
.
?- swap([1,2,3,4,5],S).
S = [2, 1, 3, 5, 4] ;
false.
it's not a true relation, since it hangs if called in mode swap(-,+), but it behaves better after uncommenting the bracketing, and providing this snippet:
:- meta_predicate when_(0).
when_(P) :-
strip_module(P,_,Q), Q =.. [_|As],
or_list(As, Exp), display(Exp),
when(Exp, P).
or_list([A], ground(A)) :- !.
or_list([A|As], (ground(A);Exp)) :- or_list(As, Exp).
edit
after #false' comments, I'm trying to explain the motivation of this answer. The requested swap/2 'function' seems to be an ideal candidate to showcase the peculiarity of Prolog data model, albeit the requested explanation (about proper syntactic usage of integer arithmetic applied to lists) is not even hinted here.
From the very start of Prolog we have available an unique mixing of relational and functional (recursive) tools, that could make little sense to a newbie. At least, it still surprises me... and I like this fact.
Now, functional logic programming, for instance Curry, attempts a solution through 'narrowing'. From the linked page:
Narrowing is useful because it allows a function to be treated as a relation: its value can be computed "in both directions"
Now, when_/1 it's a simple minded approach to the same problem. Down to earth, the swap/2 has been described as a function, but could be implemented as a relation ?
#false suggestion, adding same_length(L,S) as first goal, fixes the swap(-,+) mode, but loops on swap(-,-). The approach based on when_/1 instead reports the inability to ground the conjunction.
edit
Termination issues apart, my choice of goals order is really ineffective. Hinting this answer to another question, occurred to me that a big efficiency gain (at least, for the mode swap(+,-)) can be obtained putting constraints first:
3 ?- numlist(1,100,L), time((append([X,C,Y],L), (C=[];C=[_]), same_length(X,Y), append([Y,C,X], S))).
% 328,899 inferences, 0.125 CPU in 0.125 seconds (100% CPU, 2634422 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
X = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
C = [],
Y = [51, 52, 53, 54, 55, 56, 57, 58, 59|...],
S = [51, 52, 53, 54, 55, 56, 57, 58, 59|...]
.
4 ?- numlist(1,100,L), time(((C=[];C=[_]), same_length(X,Y), append([X,C,Y],L), append([Y,C,X], S))).
% 3,273 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 3210999 Lips)
listelements([i|o],listelements) :-
u is abs((listmax)-(listmin)),
listelements(u,listelements).
listmin([min],min).
listmin([x|y],z) :-
listmin(y,h),
min(x,h,z).
min(Q,W,Q) :-
Q =< W.
min(Q,W,W) :-
W < Q.
listmax([max],max).
listmax([a|b],c) :-
listmax(b,f),
max(a,f,c).
max(M,N,M) :-
M =< N.
max(M,N,N) :-
N < M.
Arithmetic: `listmax' is not a function
This is the error. Help please!
When I ask ?- listmin([1,2,3,4,5,6],z).
it answers false instead of 1. Why?
Considering your concrete choice of arithmetic predicates,
I guess you want to support all kinds of Prolog numbers (floating point numbers, integers, and rational numbers).
If you only work with integer numbers here then make sure you are using clpfd!
In this answer we proceed step-by-step, like this:
We define an auxiliary predicate num_num_absdiff/3 which computes the absolute difference of its first two arguments.
num_num_absdiff(X,Y,D) :-
D is abs(X-Y).
To apply num_num_absdiff/3 to all adjacent items and gather the results, we use mapadj/3:
?- mapadj(num_num_absdiff,[1,2,4,8,16,100],Ds).
Ds = [1, 2, 4, 8, 84].
The maximum absolute difference is the maximum number in above list.
We employ list_maxnum/2 to get said number.
?- list_maxnum([1,2,4,8,84], Max).
Max = 84.
Let's put it all together and define maxabsdiff_of/2:
maxabsdiff_of(D,Nums) :-
mapadj(num_num_absdiff,Nums,Ds),
list_maxnum(Ds,D).
Here are some sample queries:
?- maxabsdiff_of(D,[1,2,3,4,5,6]). % as given by the OP
D = 1.
?- maxabsdiff_of(D,[1,2,3,4,5,6,8]).
D = 2.
?- maxabsdiff_of(D,[1,2,3,100,4,5,6,8]).
D = 97.
Of course, you could also use lambda together with meta-predicate foldl/4, like so:
:- use_module(library(lambda)).
maxabsdiff_of(X,[V0,V1|Vs]) :-
foldl(\E^(E0+D0)^(E+D)^(D is max(D0,abs(E-E0))), Vs, V1+abs(V1-V0),_+X).
Sample queries:
?- maxabsdiff_of(D,[1,2,3,4,5,6]).
D = 1.
?- maxabsdiff_of(D,[1,2,3,4,5,6,8]).
D = 2.
?- maxabsdiff_of(D,[1,2,3,100,4,5,6,8]).
D = 97.
Same results as before!
I am working on a longer problem that has me duplicate an element N times in list form, and I believe that using append is the right way to go for this. The tiny predicate should theoretically act like this:
?- repl(x,5,L).
L = [x, x, x, x, x] ;
false.
I cannot seem to find any tips for this online, the replication of a single element, but I believe we need to use append, but no recursive solution. I come from more of a Haskell background, where this problem would be much easier to perform. Can someone help get me started on this? :)
Mine so far:
repl(E, N, R) :-
N > 0, append([E], [], R), writeln(R), repl(E, N-1, R), fail.
Which gives me:
?- repl(x,5,L).
[x]
[x]
[x]
[x]
[x]
false.
Close but not quite!
A recursive approach would be straight-forward and would work. I recommend figuring that one out. But here's a fun alternative:
repl(X, N, L) :-
length(L, N),
maplist(=(X), L).
If N is instantiated, then length(L, N) will generate a list of length N of just "blanks" (don't care terms). Then maplist(=(X), L) will unify each element of L with the variable X.
This gives a nice, relational approach and yields sensible results in the general case:
| ?- repl(X, N, L).
L = []
N = 0 ? ;
L = [X]
N = 1 ? ;
L = [X,X]
N = 2 ? ;
| ?- repl(X, N, [x,x,x]).
N = 3
X = x
yes
...
To figure out a recursive case, think about what your base case looks like (it would be repl with a count of 0 - what does the list look like then?). In the recursive case, think in terms of:
repl(X, N, [X|T]) :- ...
Meaning: The list [X|T] is the element X repeated N times if.... Figure out if what? If your base case is length 0, then your recursion is probably going to describe the repl of a list of length N in terms of the repl of a list of length N-1. Don't forget in this recursive rule to ensure N > 0 to avoid infinite recursion on backtracking. If you don't need the predicate to be purely relational and assume N is instantiated, then it can be fairly simple.
If you make a simple recursive version, you can "wrap" it in this predicate to make it work with variable N:
repl(X, N, L) :-
length(L, N),
simple_recursive_repl(X, N, L).
...
Because length/2 is relational, it is much more useful than just providing the length o a given list. When N and L are not instantiated, it becomes a generator of variable lists, starting at length 0. Type, length(L, N). at the Prolog prompt and see what happens.
Determinism
You give the following example of the predicate you envision:
?- repl(x,5,L).
L = [x, x, x, x, x] ;
false.
Notice that the ; is not very productive here. If you want to repeat x 5 times, then this can be done in exactly one way. I would therefore specify this predicate as deterministic not nondeterministic as you are doing.
Repeating list
Your code is actually quite far off a working solution, despite the output looking quite close in spirit to the envisioned result. You try to define the base case and the recursive case at the same time, which will not work.
Here is a simple (but less fun than #lurker gave :-)) implementation of the base and recursive case:
repeating_list(_, 0, []):- !.
repeating_list(H, Reps1, [H|T]):-
Reps2 is Reps1 - 1,
repeating_list(H, Reps2, T).
In a sense #lurker's implementation is simpler, and it is surely shorter.
Some extensions
In real-world/production code you would like to catch type errors and treat different instantiations with the same predicate. The second clause checks whether a given list consists of repeating elements (and if so, which one and how many occurrences there are).
%! repeating_list(+Term:term, +Repeats:integer, -List:list(term)) is det.
%! repeating_list(?Term:term, ?Repeats:integer, +List:list(term)) is det.
repeating_list(_, 0, []):- !.
% The term and number of repetitions are known given the list.
repeating_list(H, Reps, L):-
nonvar(L), !,
L = [H|T],
forall(
member(X, T),
% ==/2, since `[a,X]` does not contain 2 repetitions of `a`.
X == H
),
length([H|T], Reps).
% Repetitions is given, then we generate the list.
repeating_list(H, Reps1, [H|T]):-
must_be(nonneg, Reps1), !,
Reps2 is Reps1 - 1,
repeating_list(H, Reps2, T).
% Repetitions is not `nonneg`.
repeating_list(_, Reps, _):-
domain_error(nonneg, Reps).
Notice that I throw a domain error in case the number of repetitions is negative. This uses library error in SWI-Prolog. If your Prolog does not support this feature, then you may leave the last clause out.
PS: Comparison to Haskell
The combination of your statement that you do not know how to solve this problem in Prolog and your statement that this problem can be solved much easier in Haskell seems a little strange to me. I think you can only compare the difficulty of two implementations once you know how both of them look like.
I do prefer findall/3 to build lists, and between/3 to work with ranges:
repl(E, N, L) :- findall(E, between(1, N, _), L).
I have to create list of n elements for example,
do_list(5,L1).
should return,
L1=[1,2,3,4,5].
This is what I have, but it's not working.
do_list(X,L1):- X1 is X-1, do_list(X1,[X1|L1]).
do_list(0,[]).
If you want to create a list of consecutive numbers from 1 to N you can use builtin predicates findall/3 and between/3 this way:
do_list(N, L):-
findall(Num, between(1, N, Num), L).
?- do_list(5,L).
L = [1, 2, 3, 4, 5].
SWI also has another builtin which does just that, numlist/3:
?- numlist(1,5,L).
L = [1, 2, 3, 4, 5].
There are three problems with your code. The first problem is that you add X1 to the list in the clause body, but you never pass the new list back towards the head of the clause. I.e., L1 is an accumulator variable, but you need a third argument that will be bound to the final list.
The second is that the second clause only matches if the input list is empty. This will never be the case, since you add X1 to the list before calling do_list/2 recursively. I.e., you don't have a recursion anchor, and the goal ?- do_list(5,L) will never return.
The third problem is that you add X1 to the list instead of X. You'd skip the largest number.
This is how it should work:
do_list(N, L) :- do_list1(N, [], L).
do_list1(0, L, L) :- !.
do_list1(N, R, L) :- N > 0, N1 is N-1, do_list1(N1, [N|R], L).
Or if you don't want to use any built-in function (like me, when I tried this as a practice and then run into this question), you can use this (working but not effective) solution:
connect([],X,X).
connect([H|T],C,[H|T2]) :- connect(T,C,T2).
revert([],[]).
revert([H|T],R) :- revert(T,Trev), connect(Trev,[H],R)
do_revlist(0,[]).
do_revlist(X,[X|L]) :- X1 is X-1, do_revlist(X1,L).
do_list(X,L2) :- do_revlist(X,L), revert(L,L2).
P.S. Works only for positive integers.
Another solution similar to that of twinterer but without cut or predefined predicates, employing an accumulator.
do_List(Max,L) :- do_ListAcc(1,Max,L). % call Accumulator
do_ListAcc(N,N,[N]). % N=:=N ends recursion
do_ListAcc(Min,Max,[Min|Succs]) :-
Next is Min + 1,
do_ListAcc(Next,Max,Succs).
This also works only for positive integers.