Related
the Prolog notation of prefix/suffix is a quite easy one:
It pretty much puts all the work on append.
For those who don't know:
prefix(P,L):-append(P,_,L).
suffix(S,L):-append(_,S,L).
Now this means, that the result for prefix(X,[a,b,c,d]).
will be: X=[];X=[a];X=[a,b];X=[a,b,c];X=[a,b,c,d]
Here is my problem with this: I want a "real" prefix. Hence, a prefix cannot be empty, nor can the part following it be empty.
So the result to the query prefix(X,[a,b,c,d]). should be
X=[a];X=[a,b];X=[a,b,c]
and that's it.
Unfortunately, the real beaty of the standard-built in prefix predicate is, that it can use the termination of append, which is append([],Y,Y).
So it is pretty easy to know when to stop, picking the list apart one by one till the list is empty.
My termination means: Stop if there is exactly one element left in your list.
How do I do this?
My naive result would be:
prefix(P,L):-
length(P,1),append(P,E,L),E/=[].
This feels wrong though. I'm at work so I haven't checked if this actually works, but it should:
Is there any more convenient way to do this?
Same goes for suffix, which will be even harder since you do not have a way to adress the Tail as specific as the Head, I guess I'd just reverse the whole thing and then call prefix on it.
Infix will just be a combination of two.
I hope it is clear what I mean. Thanks for your input!
tl;dr: How to write a predicate prefix/2 which only filters real prefixes, so the prefix itself can not be empty, nor can the list followed by it be empty.
For the real prefix, you can try to do it like this:
list_prefix(List, [H|T]) :-
append([H|T], [_|_], List).
This just says that the first argument must have at least one element, and the rest of the list must have at least one element.
And following the suggestion by #false to make it more explicit:
list_real_prefix(List, Prefix) :-
Prefix = [_|_],
Rest = [_|_],
append(Prefix, Rest, List).
The "real" suffix will be exactly the same:
list_real_suffix(List, Suffix) :-
Front = [_|_],
Suffix = [_|_],
append(Front, Suffix, List).
You can also use a DCG for this, which is descriptive:
list_prefix(P) --> non_empty_seq(P), non_empty_seq(_).
non_empty_seq([X]) --> [X].
non_empty_seq([X|Xs]) --> [X], non_empty_seq(Xs).
| ?- phrase(list_pref(P), [a,b,c,d]).
P = [a] ? a
P = [a,b]
P = [a,b,c]
no
| ?-
You can define the suffix similarly:
list_suffix(S) --> non_empty_seq(_), non_empty_seq(S).
I am interested in performing a long concatenation of lists, using Prolog language.
The objective is to define a predicate that gets an unknown number of lists, and concatenates them all into one list (that is given as the second argument to the predicate).
I know I should first understand how Prolog supports arguments with unbounded size, but I think the answer to that is using lists, for example:
[a | [[b,c,d] | [[e,f,g] | [h,i,j,k]]]].
If so, I thought about writing the predicate somewhat like this:
l_conc([ ],[ ]).
l_conc([[ ]|Tail],L):-
l_conc(Tail,L).
l_conc([[Head|L1]|Tail],[Head|L2]):-
l_conc([L1|Tail],L2).
However, it only concatenates empty lists to one another.
Please help me here (both regarding the arguments representation and the predicate itself) :-) Thanks!
Before I answer the actual question, I have a couple of comments.
First, the term you give as an example [a | [[b,c,d] | [[e,f,g] | [h,i,j,k]]]] can be written more compactly in Prolog. You can use the Prolog toplevel itself to see what this term actually is:
?- Ls = [a | [[b,c,d] | [[e,f,g] | [h,i,j,k]]]].
Ls = [a, [b, c, d], [e, f, g], h, i, j, k].
From this, you see that this is just a list. However, it is not a list of lists, because the atoms a, h, i etc. are not lists.
Therefore, your example does not match your question. There are ways to "flatten" lists, but I can only recommend against flattening because it is not a pure relation. The reason is that [X] is considered a "flat" list, but X = [a,b,c] makes [[a,b,c]] not flat, so you will run into logical inconsistencies if you use flatten/2.
What I recommend instead is append/2. The easiest way to implement it is to use a DCG (dcg). Consider for example:
together([]) --> [].
together([Ls|Lss]) -->
list(Ls),
together(Lss).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
Example query:
?- phrase(together([[a],[b,c],[d]]), Ls).
Ls = [a, b, c, d].
In this example, precisely one level of nesting has been removed.
I'm trying to write a predicate to remove the head from every list in list of lists and add the tails to a new list. The resulting list should be returned as the second parameter.
Here's the attempt:
construct_new(S,New) :-
New = [],
new_situation(S,New).
new_situation([],_).
new_situation([H|T], New) :-
chop(H, H1),
new_situation(T, [H1|New]).
chop([_|T], T).
You would call it like this:
construct_new([[x,x],[b,c],[d,e,f]],S).
This, however, only produces output true..
Step-by-step execution
Your query is construct_new(Input,Output), for some instanciated Input list.
The first statement in construct_new/2 unifies Output (a.k.a. New) with the empty list. Where is the returned list supposed to be available for the caller? Both arguments are now unified.
You call new_situation(Input,[])
You match the second clause new_situation([H|T],[]), which performs its task recursively (step 4, ...), until ...
You reach new_situation([],_), which successfully discards the intermediate list you built.
Solutions
Write a simple recursive predicate:
new_situation([],[]).
new_situation([[_|L]|T],[L|R]) :-
new_situation(T,R).
Use maplist:
construct_new(S,R) :-
maplist(chop,S,R).
Remark
As pointed out by other answers and comments, your predicates are badly named. construct_new is not a relation, but an action, and could be used to represent almost anything. I tend to like chop because it clearly conveys the act of beheading, but this is not an appropriate name for a relation. repeat's list_head_tail(L,H,T) is declarative and associates variables to their roles. When using maplist, the other predicate (new_situation) doesn't even need to exist...
...even though guillotine/3 is tempting.
This could be done with a DCG:
owth(Lists, Tails) :-
phrase(tails(Tails), Lists).
tails([]) --> [].
tails([T|Tails]) --> [[_|T]], tails(Tails).
Yielding these queries:
| ?- owth([[x,x],[b,c],[d,e,f]], T).
T = [[x],[c],[e,f]] ? ;
no
| ?- owth(L, [[x],[c],[e,f]]).
L = [[_,x],[_,c],[_,e,f]]
yes
(owth = Off with their heads! or, if used the other direction, On with their heads!)
If you also want to capture the heads, you can enhance it as follows:
owth(Lists, Heads, Tails) :-
phrase(tails(Heads, Tails), Lists).
tails([], []) --> [].
tails([H|Hs], [T|Tails]) --> [[H|T]], tails(Hs, Tails).
We use meta-predicate maplist/[3-4] with one of these following auxiliary predicates:
list_tail([_|Xs],Xs).
list_head_tail([X|Xs],X,Xs).
Let's run some queries!
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],Heads,Tails).
Heads = [x,b,d],
Tails = [[x],[c],[e,f]].
If you are only interested in the tails, use maplist/4 together with list_head_tail/3 ...
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],_,Tails).
Tails = [[x],[c],[e,f]].
... or, even simpler, maplist/3 in tandem with list_tail/2:
?- maplist(list_tail,[[x,x],[b,c],[d,e,f]],Tails).
Tails = [[x],[c],[e,f]].
You can also use the somewhat ugly one-liner with findall/3:
?- L = [[x,x],[b,c],[d,e,f]],
findall(T, ( member(M, L), append([_], T, M) ), R).
R = [[x], [c], [e, f]].
(OK, technically a two-liner. Either way, you don't even need to define a helper predicate.)
But definitely prefer the maplist solution that uses chop as shown above.
If you do the maplist expansion by hand, and name your chop/2 a bit better, you would get:
lists_tails([], []).
lists_tails([X|Xs], [T|Ts]) :-
list_tail(X, T),
lists_tails(Xs, Ts).
And since you can do unification in the head of the predicate, you can transform this to:
lists_tails([], []).
lists_tails([[_|T]|Xs], [T|Ts]) :-
lists_tails(Xs, Ts).
But this is identical to what you have in the other answer.
Exercise: why can't we say:
?- maplist(append([_]), R, [[x,x],[b,c],[d,e,f]]).
How can I check if an element in the list is an empty list: [] ?
I've got the following:
display_degrees([A,B,C,D]):- write(B).
display_degrees([A,B,C,D]):- B==[], nl,write('has no degree'), nl, !.
When I enter in something like:
display_degrees([1,[],3,4]).
I just get: [] instead of 'has no degree'. Is my syntax wrong? Can I not add a clause to this predicate like this?
You're getting this behavior because proof search stops when a goal has succeeded. When you type
display_degrees([1,[],3,4]).
the first rule unifies, and it writes B. Since it was a success, it stops. You can ask Prolog to keep searching, and then it will find the second clause. In swipl, I get
?- [foo].
?- display_degrees([1,[],3,4]).
[]
true r % I type 'r' there
has no degree
true.
If you're just learning Prolog, I suggest you avoid the cut operator ! for some time. Also, doing IO is not the most intuitive thing. I would try some exercises with defining things like natural numbers and recursive functions. E.g., plus:
plus(z, X, X).
plus(s(X), Y, s(Z)) :- plus(X, Y, Z).
The problem with what you have is that the more general rule will fire first. You could switch the order:
display_degrees([A,[],C,D]) :- nl, write('has no degree'), nl, !.
display_degrees([A,B,C,D]) :- write(B).
I could just as well have written for the first predicate:
display_degrees([A,B,C,D]) :- B == [], nl, write('has no degree'), nl, !.
But the "shortcut" I show initially is more idiomatic for a Prolog predicate like this.
I kept the cut since you know you deterministically want one choice. The first rule will match if and only if the second list element is [].
| ?- display_degrees([1,[],3,4]).
has no degree
yes
| ?- display_degrees([1,2,3,4]).
2
yes
| ?-
I'm new to prolog and I just can't figure this out.
I'm trying to build a simple program that receives a list of predicates, searches for a specific predicate in the list, and applies a function to that predicate's parameters.
Something along these lines:
?- program([pred1(a,b,p), pred2(d,b,p), pred2 (a,c,p)]).
program (list1) :-
search(pred2(X,Y,p),list1).
doSomething (X,Y) % with the X and Y returned from search function, both of them.
Basically, I want to use all values that would return from an objective search(pred2(X,Y,p),list1) and use them on another function.
Okay, I tried some stuff in prolog and came to this:
member(X, [X | _]).
member(X, [_ | R]) :- member(X, R).
prog(L1,Out) :- member(pred2(X,Y), L1).
?- prog ([(pred1(a,b),pred2(c,b),pred2(d,a)],Out).
It gives true 2 times as it is supposed to, but I wanted to get Out = [c,b] and Out = [d,a]. How I can achieve this?
Regarding Oak's answer: I get that it isn't a procedural language but I can't figure out how to access values and use them in prolog. Your example wasn't that helpful.
For starters, I would avoiding calling these things "functions". Prolog is not a procedural language, and rules / predicates are not functions.
Basically, when you use a rule you're really asking Prolog, "give me all the values which will satisfy this rule". The rule, by itself, does not return anything.
So say you had the following in a procedural language:
f(g(3))
How would you do it in Prolog? You would need to write some predicate f(X,Y) and some predicate g(X,Y), and then you would need to use the query f(3,Y), g(Y,Z) - which means to ask Prolog to find you values for Y and Z which will satisfy this. Z is what you're interested in.
the best way to approach these filter & project requirements in prolog in my opinion is to write your filter expression such that it takes one argument and succeeds if the input argument passes the filter -
iseven(Num) :- 0 is Num % 2 .
Then write the the projection code as taking one argument that is the input, and one that is the output -
triple(NumIn, NumOut) :- NumOut is NumIn * 3 .
Then tie them together -
triple_evens(NumIn, NumOut) :- iseven(NumIn), triple(NumIn, NumOut).
Then to run this on every member of a list, we should use findall -
triple_evens_in_list(Lin, Lout) :-
findall(Num, ( member(NumL, Lin),
triple_evens(NumL, Num)
), LOut).
This could be generalized to take as arguments the name of the filter & map predicates of course. And it could be compressed down to one stmt too in the form -
findall(Num, ( member(M, List), 0 is M % 2, Num is M * 3 ), ListOut).