Prologue: take the first "N" elements of the list
I need to write a Prolog predicate take(L, N, L1)
that succeeds if the list L1
contains the first N
elements of the list L
in the same order. For example:
?- take([5,1,2,7], 3, L1). L1 = [5,1,2] ?- take([5,1,2,7], 10, L1). L1 = [5,1,2,7]
The prologue still doesn't make any sense to me and it's hard for me to break it. Here's what I have so far:
take([H|T], 0, []).
take([H|T], N, L1) :-
take(T, X, L2),
X is N-1.
Could you please explain what I did wrong here?
source to share
Here is a definition that implements the relational counterpart take
in functional languages ββlike Haskell 1 . First, the order of the arguments must be different, which makes partial application easier. There is a cut, but only after checking for an error inline (=<)/2
that throws instantiation_error
if the argument contains a variable.
take(N, _, Xs) :- N =< 0, !, N =:= 0, Xs = []. take(_, [], []). take(N, [X|Xs], [X|Ys]) :- M is N-1, take(M, Xs, Ys). | ?- take(2, Xs, Ys). Xs = [], Ys = [] ? ; Xs = [_A], Ys = [_A] ? ; Xs = [_A,_B|_C], Ys = [_A,_B] ? ; no
Notice how the above query is read:
How to take 2 elements from
Xs
to getYs
?
And there are 3 different answers. If Xs
empty, then and Ys
. If Xs
is a list with one element, then and Ys
. If it Xs
has at least 2 elements, then these two are Ys
.
1) The only difference is that it take(-1, Xs,Ys)
fails (for everyone Xs, Ys
). Probably best would be to release something domain_error
likearg(-1,s(1),2)
source to share
The @CapelliC code above works if the instantiation is correct ; if not, it might show erroneous behavior:
? - take (Es, 0, Xs). ** LOOPS ** % trouble: goal does not terminate ? - take ([ A , _], 1, [x]). true. % trouble: variable A remains unbound
To protect against this, you can use as follows: iwhen/2
take(Src, N, L) :-
iwhen(ground(N+Src), findall(E, (nth1(I,Src,E), I =< N), L)).
Examples of queries are performed with SWI-Prolog 8.0.0:
? - take ([a, b, c, d, e, f], 3, Ls). Ls = [a, b, c]. ? - take ([a, b, c, d, e, f], N , Ls). ERROR: Arguments are not sufficiently instantiated ? - take (Es, 0, Xs). ERROR: Arguments are not sufficiently instantiated ? - take ([A, _], 1, [x]). ERROR: Arguments are not sufficiently instantiated
Safer now!
source to share