Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

do something with every element of a list and do it elegantly

10 views
Skip to first unread message

Simon Strobl

unread,
Jun 17, 2008, 4:51:31 AM6/17/08
to
Hello,

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.

Jan Wielemaker

unread,
Jun 17, 2008, 5:21:18 AM6/17/08
to
On 2008-06-17, Simon Strobl <Simon....@gmail.com> wrote:
> Hello,
>
> 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).

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

Simon Strobl

unread,
Jun 17, 2008, 6:18:30 AM6/17/08
to
Hello 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


Chip Eastham

unread,
Jun 17, 2008, 2:36:34 PM6/17/08
to

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

Joachim Schimpf

unread,
Jun 17, 2008, 7:18:10 PM6/17/08
to

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

Jan Wielemaker

unread,
Jun 18, 2008, 3:37:14 AM6/18/08
to
On 2008-06-17, Joachim Schimpf <jsch...@cisco.com> 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.

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

Simon Strobl

unread,
Jun 18, 2008, 3:59:26 AM6/18/08
to
> What you want (I claim ;-)) is ECLiPSe's do-loop construct, which
> was motivated more or less by the points you mention, seehttp://eclipse-clp.org/software/loops/index.html


This sounds interesting. Unfortunately, the slides cannot be
downloaded.

Joachim Schimpf

unread,
Jun 18, 2008, 8:05:29 AM6/18/08
to

Sorry, broken links fixed now!

tomena...@gmail.com

unread,
Jun 19, 2008, 2:33:30 AM6/19/08
to

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

0 new messages