I am currently practicing Prolog for an exam and when I studied old exams I came across a problem, where one had to define a predicate which returns the length of a list. (Example: lengthof([a,b,c,d,e,f],Length). evaluates to Length=6.)
My approach was the following:
lengthof([],0).
lengthof(List,LengthNew) :- lengthof([_|List],Length),LengthNew is Length-1.
But it always threw a stack overflow error. I didn't know what I could have done wrong, so I took a look into the solutions. The solution for this problem is the following:
lengthof([],0).
lengthof([_|List],LengthNew) :- lengthof(List,Length),LengthNew is Length+1.
I am now wondering why my approach did not work out. What is wrong with this one? Logically and at first look, I think, that both approaches are equivalent.
lengthof([],0).
this string means that legth of empty list is zero.
lengthof([_|List],LengthNew) :-
lengthof(List,Length),LengthNew is Length+1.
in the rule you say, that no empty list has to consider as first element (_) and other elements (List). And that length of the all list is length of "List" plus one.
But in this rule:
lengthof(List,LengthNew) :-
lengthof([_|List],Length),LengthNew is Length-1.
you say that length of initial list ("List") is length of more big list minus one.
It is true for any list, but it is no solution of your problem, because your code does not calculate length of initial list - instead of this you inclrease initial list endlessly.
Your first rule that process empty list desribes condition of recursion exit. So your second rule must decrease size of list, but you try increase it, so you receive "stack overflow" error.
Related
I am trying to write a predicate that succeeds if and only if the numbers in the list are in non-decreasing order. I am having a hard time trying to figure this out. I know that if each element is less than or equal to the previous one then it should return false but I am lost on how to do it.
ordered(L) :-
Recursion should usually be your first thought for approaching any problem in Prolog. This means:
Defining a base case, where you can easily determine that the predicate is true or false
In other cases, splitting the problem into parts - one part you can resolve immediately, another you can resolve recursively. These parts of the problem generally correspond to portions of the list.
In the simplest cases, the recursive logic is simply to apply some test to the first element of the list; if it passes, recursively apply the predicate to the remainder of the list.
In your case I think it is a bit more complex, as there is no meaningful way you can test an individual element for orderedness (and maybe that gives you a hint what the base case is ...).
ordered(L) :- ordered2(L).
% empty list is ordered
ordered2([]) :- true.
% list with one element is ordered
ordered2([_]) :- true.
% list is ordered if two first elements are ordered
% and the rest of list is ordered
ordered2([A,B|T]) :- A=<B, ordered2([B|T]).
Given a list (A) I want to be able to create a new list (B) that contains only the elements of A that are the smallest or the biggest compared to their next and previous element. My problem is that I don't know how to do the comparisons of each element with its previous one.
(This question may be silly but I'm new to prolog and any help would be appreciated.)
You could start with something like that:
compareElem([]).
compareElem([H,H1,H2|B]):-compareElem(B),
compare(?Order, H1,H2),
compare(?Order, H1, H).
where ?Order is the order of comparison (like '<' or '>'). See compare/3.
Some queries:
?- compareElem([1,2,3,4,5,6]).
true.
?- compareElem([1,2,3,4,5,3]).
false.
of course to apply this example you must ensure that the list has 3n elements, this is just a basic example. Together with this comparison you can generate the other list
I'd like to return the depth level or number of nested list where certain element is. Also as condition the list doesn't have repeated elements. I am trying to understand this solution where I have two main doubts:
profundidad([],_,0):-!.
profundidad([A],A,1):-!.
profundidad([A|_],A,1):-!.
profundidad([H|_],A,N):-
profundidad(H,A,R),N is R+1.
profundidad([_|X],A,N):-
profundidad(X,A,N),!.
The correct output would be:
profundidad([2,3,4,5,[[6]],10],6,X).
X = 3
First, why we do put the cut operator ! from 1-3 statements? I know it prevents compiler from considering later statements when a solution is found.
Second, how we could read 4th and 5th cases in natural language?
The depth of an element A when the list is splitted by the head H and the rest _, is equal to the number R of steps plus 1.
profundidad([H|_],A,N):-
profundidad(H,A,R),N is R+1.
And those two sentences I think they are the same as previous ones but to go forward into the list:
profundidad([_|X],A,N):-
profundidad(X,A,N),!.
Plus, I am doubting now about why to not put [] into recursive called to:
profundidad(X,A,N),!.
I think it is to go deep into the nested lists but I am not sure.
Thank you.
It's better to avoid cuts when possible, in the following rewrite and simplification the test H\=A make the three clauses disjunctive.
profundidad([A|_],A,1).
profundidad([H|_],A,N):-
% H\=A,
profundidad(H,A,R),
N is R+1.
profundidad([H|T],A,N):-
H\=A,
profundidad(T,A,N).
The second clause doesn't need the test, since it goes down a level in the list, meaning it will succeed when it's a list, and then cannot unify with the target element anyway. For clarity it could stay there - it doesn't harm.
If your Prolog has dif/2, you could use that instead of (\=)/2, depending on your requirements about the generality (WRT variables instantiation) of the solution.
I am trying to write a relation split in Prolog that takes an integer N, a list L of integers, and other parameters, list L is flat. The relation split returns true if the list L can be divided into three subsets, such that the sum of the integers in each subset is strictly less than N. Otherwise, the relation returns false. This is the furthest I've gone so far:
split(list, list, list, list)
split([],[],[],[]).
list_sum([],0).
split([X|L], [X|L1], [X|L2], L3):-
list_sum([Head + Tail]),
list_sum>N,
!,
split(N, L,L1, L2, L3).
?- ERROR: toplevel: Undefined procedure: list_sum/2 (DWIM could not correct goal)
Any help and explanation is highly appreciated.
Basically your problem is that you need to go learn Prolog. I'm not kidding. You're going to fail your class if you think you can get away with this level of "not getting it" and pick up the rest on S.O.
What's that first line, a comment? Put the comment character there.
What is list_sum/2 doing there in the middle of your split/4 definition?
Unless you're trying to create some kind of difference list or destructuring arithmetic, [Head + Tail] will absolutely not do what you want.
What is list_sum>N supposed to mean on the next line? There is only one namespace in Prolog and the language is very, very dependent on getting your capitalization right. Being this sloppy does not bode well.
Why are you cutting on line 7?
Your last line is defining split/5 when the previous two rule heads (I think?) are defining split/4. This cannot be what you mean.
You're pattern-matching on line 4 requires that all three of the lists begin with the same value, which seems like a pretty special special-case considering you have no other in which you meaningfully examine the elements of the lists.
In my opinion this code is totally unsalvagable. Throw it away and start over. And read through a tutorial first.
To your exact question: you have not defined a predicate list_sum with two arguments in the "code" that you have shown. This is what the error is telling you.
While learning Prolog, I'm trying to solve the following problem, using accumulators:
Write a predicate addone2/ whose first argument is a list of integers, and whose second argument is the list of integers obtained by adding 1 to each integer in the first list. For example, the query
addone([1,2,7,2],X).
should give
X = [2,3,8,3].
I created the following code:
addone([], _).
addone([E|Tail], [R|Rs]) :-
NewE is E+1,
append([R|Rs], [NewE], NewRs),
addone(Tail, NewRs).
But it's not working. Can someone tell me why? So, how do I use accumulators in Prolog?
Thanks!
anthares is correct in that you have to refine your base case. However, you are also making things very inefficiently with your append calls. In Prolog, it takes some time to get used to the power of unification, but for example, in this case it helps you to immediately set up your result list. Try the following:
addone([E|Tail], [E1|Rs]) :-
E1 is E+1,
addone(Tail, Rs).
That's really all there is to it. By immediately placing E1 in your second argument's pattern, you have already created the first element of your result list. The remaining elements Rs will be created during the recursion. A very typical Prolog pattern.
The bottom of your recursion should be addone([],[]). in order NewRs to be connected with the []