What is the simplest way to roll a list ?
Consider the following list :
myList : [0,1,4,6,3]
I am looking for a roll() function that would do :
(%i0) roll(myList,1)
(%o0) [3,0,1,4,6]
(%i1) roll(myList,-1)
(%o1) [1,4,6,3,0]
I can achieve the same result by calling :
myItem : pop(myList)
myList : append(myList,myItem)
Problem is that this works in one direction only (there is no pop_back() function to my knowledge (?)) and that it is a two liner. Any better way to do that ?
Well, there isn't a built-in function for that. But I think you can use rest to get the effect you want.
(%i10) rotate (e, n) :=
if atom(e) then e
else block ([a : args(e)],
apply (op(e),
append (rest (a, length(a) - n), rest (a, -n)))) $
(%i11) foo : [a, b, c, d, e, f, g];
(%o11) [a, b, c, d, e, f, g]
(%i12) rotate (foo, 2);
(%o12) [f, g, a, b, c, d, e]
(%i13) rotate (foo, 7);
(%o13) [a, b, c, d, e, f, g]
This works for all expressions, not just lists.
(%i16) rotate (f(1,2,3), 2);
(%o16) f(2, 3, 1)
This implementation doesn't take negative n or n greater than the number of arguments, although I think it would be easy to handle that.
I've assumed that rotate moves elements at lesser indices into greater indices. Again, if you want the default to go in the other direction, I think it would be easy to do that.
EDIT: Actually it isn't necessary to separate out op(e) and args(e). You can call rest(e, ...) when e is not a list and it does the right thing. So a more concise version is:
rotate (e, n) :=
if atom(e) then e
else append (rest (e, length(e) - n), rest (e, -n)) $
Related
I made some predicate, which saves a very complex list into a variable P.
Let's say:
pred(P) :-
P = [[1, a, b, c, 234],d].
Now I want to put this list into another predicate, let's say
pred2(P, L) :-
nth1(2, P, L).
My problem now is, I don't want to copy [[1, a, b, c, 234], d] as parameter into P. Is their a simple way, maybe to define an atom or another shortcut, e.g. 'test' := [[1, a, b, c, 234],d]. and call ?- pred2('test', L)?
The simple way is to call the predicate which you've defined:
pred2(L) :-
pred(P), % :- P = [[1, a, b, c, 234],d].
nth1(2, P, L).
This will "set" nay instantiate the logical variable P first, then use it to "set" L.
Note P has become an internal variable here. You don't have to set it when calling pred2. pred2 will call pred for you, to set P.
So far I've done my fair amount of research and I've tried different methods, however even after reading multiple stack overflow answers and even a PDF from Addison Wesley, I can't find the way to do it. Here is the code
use_module(library(func)).
% importing library "func"
scale([c, d, e, f, g, a, b]).
scale(c, major, [c, d, e, f, g, a, b]).
scale(c, minor, [c, d, e_b, f, g, a_b, b_b]).
%1st attempt
search(note, scale):- scale(note, scale).
%2nd attempt
scaleOf(note, type_scale):- scale(note, type_scale).
on(item,[item|rest]).
on(item,[disregardHead|tail]):-
scale(tail),
on(item, tail).
%3rd attempt
fatherOf(father,type, son):- scale(father, type, sons), search(son, type, sons).
search(son, type, []):- !, fail.
search(son, type, [son|l]):- !, true.
search(son, type, [c|l]):- search(son, type, l).
What am I attempting? Simple, something that can iterate through the predicate scale(c, [c, d, e, f, g, a, b]). But I can't get it right.
Edit: I have multiple predicates because someone else suggested creating a predicate that would differentiate one scale from the other. I thought I could cram it inside any algorithm but I guess PROLOG is not that lenient :p
You can do that with member/2 [swi-doc]. This can be used to search, unify with a member, or generate a list.
So you can search with:
search(Note, Scale, Item) :-
scale(Note, Scale, Items),
member(Item, Items).
It is important that Note, Scale, Item and Items start with an Uppercase, since identifiers with a lower case are constants or functors. Identifiers with an uppercase are variables.
This will thus unify Item with the items in the list, for the given sample data we for example obtain:
?- search(c, minor, Item).
Item = c ;
Item = d ;
Item = e_b ;
Item = f ;
Item = g ;
Item = a_b ;
Item = b_b.
So I am trying to
I am defining the sets with is_a(b, a), is_a(c, a), which for simplicity would look visually something like this:
a
b c
d e f g
I want to give in the list [b, c] and as a result get the list [d, e, f, g]
At the moment when I give in a node or a variable, then it can find everything that is underneath it with this method:
find_nodes(Root, Root) :-
\+ is_a(_, Root).
find_nodes(Root, X) :-
is_a(Node, Root),
find_nodes(Node, X).
Which when run gives me the result I need :
?- find_nodes(b, X).
X = d.
X = e.
But it is not in a list, so I have tried :
?- all_nodes([b, c], X).
all_nodes([], _).
all_nodes([H|T], [R|Res]):-
findall(L, find_nodes(H, L), R),
all_nodes(T, Res).
Which gives me - X = [[d, e], [f, g]|_4040], which consists of lists within lists, but I need just 1 list, that would be X = [d, e, f, g].
What am I doing wrong here?
EDIT
Like #lurker said findall returns a list and adding list to a list will give the result I get right now.
The one thing I also tried was using:
all_nodes([], _).
all_nodes([H|T], [R|Res]):-
find_nodes(H, R),
all_nodes(T, Res).
But well that one does not work either because It only gives me 1 element, which in this case is d and then f.
You can take advantage of the de facto standard findall/4 (*) predicate to solve the problem. This predicate is a variant of the standard findall/3 predicate that allows passing a tail for the list of solutions collected by the predicate. For example:
?- findall(N, (N=1; N=2; N=3), L, [4,5]).
L = [1, 2, 3, 4, 5].
In the following solution, I have renamed predicates and variables for clarity and modified your node leaf predicate:
is_a(a, b).
is_a(a, c).
is_a(b, d).
is_a(b, e).
is_a(c, f).
is_a(c, g).
leaf(Leaf, Leaf) :-
\+ is_a(Leaf, _).
leaf(Node, Leaf) :-
is_a(Node, Child),
leaf(Child, Leaf).
all_nodes([], []).
all_nodes([Node| Nodes], Leaves):-
findall(Leaf, leaf(Node, Leaf), Leaves, Tail),
all_nodes(Nodes, Tail).
Sample calls:
?- all_nodes([b, c], X).
X = [d, e, f, g].
?- all_nodes([a], X).
X = [d, e, f, g].
?- all_nodes([b], X).
X = [d, e].
(*) It's a built-in predicate in GNU Prolog, JIProlog, Lean Prolog, O-Prolog, SICStus Prolog, SWI-Prolog, XSB, and YAP (possibly others).
I am facing a prolog problem regarding List and Term. Then my question is how to write a predicate
transform([a,b],X)
will return X = (a,b) Or vice versa
This is weird with me because I've never faced such term before. I tried with the built in =.. but
=..((a,b,c,d),X)
returns X=[',',a,(b,c,d)] which makes me deeply disappoint.
Thank you.
Check something like this:
transform([A], A):-
A=..[_].
transform([A,B], (A,B)):-
B=..[_].
transform([A,B,C|Tail], L):-
L=..[',',A,T],
transform([B,C|Tail], T).
The first clause is only needed if you want transform([Item], Item).
?- transform([a,b], X).
X = (a, b)
?- transform([a,b,c,d,e,f], X).
X = (a, b, c, d, e, f)
?- transform(L, (a,b,c,d,e,f,g))
L = [a, b, c, d, e, f, g]
Note that the term you are building does have a functor, it is ','/2, and it is shown with the parenthesis you are seeing.
suppose i have this list in prolog:
[-0.791666666666667-[]-[predicate(a,b,c,d)]-[predicate_2(p,e,q,d,g)]]
there is way to split this in:
-0.791666666666667, [], [predicate(a,b,c,d)], [predicate_2(p,e,q,d,g)] ???
Split means have different pice of the list.
Maybe:
X = -0.791666666666667 Y = [] Z = [predicate(a,b,c,d)] etc...
Or another solution can be replace - with "," so it become a list with different elements?
You can use pattern matching. Similar to the way you use it on lists ([H|T]):
split(A, R) :- split(A, R, []).
split(A-B, R, Acc) :- split(A, R, [B|Acc]), !.
split(H, [H|T], T).
I'm using accumulator, because something like a-b-c is split by A-B into a-b and c.
EDIT: If you know you have 4 terms, you can use something like
split(A-B-C-D, A, B, C, D).
Trivial:
to_list([A-B-C-D], [A,B,C,D]).
Usage:
?- to_list([-0.791666666666667-[]-[predicate(a,b,c,d)]-[predicate_2(p,e,q,d,g)]],
L).
L = [-0.791667, [], [predicate(a, b, c, d)], [predicate_2(p, e, q, d, g)]].
Or do the pattern matching inline, it's rather wasteful to write a predicate for such a task, which seems rather one-off to me.