I’m trying to write a predicate that will take a list, a number, and a variable that will then give the first N elements of the list to the variable. I’m able to do this, but while trying to make it more flexible so that it will stop when it reaches the end of the list or when N is 0, I started getting a garbage variable returned at the end of my list.
Here is my code:
take(_,0,_) :- !.
take([],_,_) :- !.
take([Head|Tail], Number, [Head|Result]) :-
Number > 0,
N1 is Number - 1,
take(Tail, N1, Result).
and when I try to use take([1,3,5,7], 3, L1), I get L1 = [1, 3, 5|_G2028].
I think it has something to do with how I didn’t define Result as an empty list, but I don’t know how to do so, while keeping the functionality of the predicate.
Change the first 2 rules to:
From your code I can see that
takeis a predicate that returns true when the 3rd argument is the result of taking the leading elements from the list in the first argument as many as possible but less than the number specified 2nd argument.So you can constraint the output when 2nd argument is 0 to
[], since you have reached the limit.And you can constraint the output when the 1st argument is an empty list to
[], since you can’t take anything anyway.Without the constraints above, it means that anything is valid when the maximum number of elements to take is 0 or when the original list is empty.
Alternatively, you can write everything in one rule:
The length of the output list is the minimum between the length of original list and
Num, that is used as constraint to theappendto take out exactly the appropriate number of elements from the original list.