in my programs I frequently use the following pattern:
add_qs([], []).
add_qs([H|T], Qs) :-
add_q(H, HQ),
add_qs(T, Tmp),
append([HQ], Tmp, Qs).
add_q(Atom, AtomQ) :-
atom_concat(Atom, 'q', AtomQ).
The actual code is in add_q. The predicate add_qs is only necessary to
process every element of the list. Isn't there a (standard) solution
for making this (and similar) code shorter?
Simon.
This is highly unreadable to most experienced Prolog programmers
as it doesn't follow standard patterns. One expects:
add_qs([H|T], [HQ|Qs]) :-
add_q(H, HQ),
add_qs(T, Qs).
This is already shorter *and* tail-recursive. Alternatively, simply
replace the call into
...,
maplist(add_q, List, QList)
Many systems provide maplist. Normally it uses meta-calling which is,
depending on the Prolog system, (much) slower than normal calling.
SWI-Prolog (and YAP?) provide library(apply_macros) that ensures such
calls are compiled, so the result is exactly the same as writing the
code above.
> add_q(Atom, AtomQ) :-
> atom_concat(Atom, 'q', AtomQ).
>
> The actual code is in add_q. The predicate add_qs is only necessary to
> process every element of the list. Isn't there a (standard) solution
> for making this (and similar) code shorter?
Better?
--- Jan
thank you for your quick answer.
> > in my programs I frequently use the following pattern:
>
> > add_qs([], []).
>
> > add_qs([H|T], Qs) :-
> > add_q(H, HQ),
> > add_qs(T, Tmp),
> > append([HQ], Tmp, Qs).
>
> This is highly unreadable to most experienced Prolog programmers
> as it doesn't follow standard patterns. One expects:
>
> add_qs([H|T], [HQ|Qs]) :-
> add_q(H, HQ),
> add_qs(T, Qs).
Thanks for pointing this out. Yet, there was also a reason why I put
the example this way, although I did not express myself very clearly:
I wanted to make it as general as possible. Sometimes one wants to use
other predicates than append in add_qs. What I am dreaming of is a
general pattern of the type
my_pred(InputList, SomeOutputWhichDoesNotHaveToBeAList) :-
...
where ... is the actual code and no additional predicates are needed.
In the above example the actual code includes the usage of append and
the usage of atom_concat. (Which I did not say clearly in my last
post.)
> maplist(add_q, List, QList)
I did consider using maplist, but I think it has two major
disadvantages: First it is not an ISO predicate and, secondly, it does
not allow me to use only add_q and no auxiliary predicates.
Simon
I found helpful the discussion here of implementing
maplist/3 in terms of ISO predicates:
http://www.poplog.org/docs/popdocs/prolog/ploghelp/call
regards, chip
What you want (I claim ;-)) is ECLiPSe's do-loop construct, which
was motivated more or less by the points you mention, see
http://eclipse-clp.org/software/loops/index.html
Jan Wielemaker wrote:
>...
> Many systems provide maplist. Normally it uses meta-calling which is,
> depending on the Prolog system, (much) slower than normal calling.
> SWI-Prolog (and YAP?) provide library(apply_macros) that ensures such
> calls are compiled, so the result is exactly the same as writing the
> code above.
library(apply_macros) originated in ECLiPSe, and was a precursor of the
above mentioned, more flexible do-construct, which is also implemented
by macro expansion.
-- Joachim
Thanks. Added the following remark to the PlDoc comment:
The idea for this library originates from ECLiPSe and came to SWI-Prolog
through YAP.
Cheers --- Jan
This sounds interesting. Unfortunately, the slides cannot be
downloaded.
Sorry, broken links fixed now!
The next abstraction step from maplist is a function usually called
fold or reduce.
Let me call it foldlist following maplist:
foldlist(Comb,Zero,List,Result) :-
foldlist_(List,Comb,Zero,Result).
foldlist_([],_,Result,Result).
foldlist_([X|Xs],Comb,Zero,Result) :-
foldlist_(Xs,Comb,Zero,Temp),
call(Comb,X,Temp,Result).
E.g.
?- foldlist(plus,0,[1,2,3],R).
R = 6
We can define maplist in terms of foldlist:
maplist(P,List,Result) :-
foldlist(cons(P),[],List,Result).
cons(P,X,Ys,[Y|Ys]) :- call(P,X,Y).
Cheers,
Tom