maplist and friends

View: New views
8 Messages — Rating Filter:   Alert me  

maplist and friends

by Attila Bartha :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

i'm experimenting with variations on maplist and friends.
i would like more control on which arguments of the predicate will be unified with the elements of the lists.
i have came up with the following:

vmaplist(Pred, LA) :-
        term_variables(Pred, VL),
        vmaplist_a(Pred, VL, LA).

vmaplist_a(_, _, []) :- !.
vmaplist_a(Pred, VL, [A|As]) :-
        copy_term((Pred, VL), (Q, [A])),
        call(Q),
        vmaplist_a(Pred, VL, As).

vmaplist(Pred, LA, LB) :-
        term_variables(Pred, VL),
        vmaplist_a(Pred, VL, LA, LB).

vmaplist_a(_, _, [], []) :- !.
vmaplist_a(Pred, VL, [A|As], [B|Bs]) :-
        copy_term((Pred, VL), (Q, [A, B])),
        call(Q),
        vmaplist_a(Pred, VL, As, Bs).

in vmaplist/2,3 the (copy of the) free variable(s) which appear in Pred will be successively unified with the elements of the list(s) and (a copy of) Pred will be called.

in vmaplist_a Pred can have more free variables than the number of lists, and an additional list in the 2-nd position of vmaplist_a holds the vars which will be unified with the elems of the lists.

some examples:

:- vmaplist(X<10, [1,2,3]).
true.

:- vmaplist(A=B, [1,2,3], L).
L = [1,2,3].

:- vmaplist(A-B=C, [1,3,4,2], [foo,bar,baz,kix], L),
keysort(L, S),
vmaplist(A=B-C, S, X, Y).
L = [1-foo, 3-bar, 4-baz, 2-kix],
S = [1-foo, 2-kix, 3-bar, 4-baz],
X = [1, 2, 3, 4],
Y = [foo, kix, bar, baz].

vmaplist_a((numlist(1,N,L),format('~w ~w~n',[N, L])), [N], [1,3]).
1 [1]
3 [1, 2, 3]

vmaplist has about half the speed of maplist.
i suppose a lot of garbage is created because of copy_term.

vmaplist relies on the observation that term_variables gives the free vars in the order in which they appear in the text of Pred.
i have tested this on cases like :
  term_variables(pred(A, foo(B)), L). =>  L= [A,B]).
  term_variables(pred(foo(A), B)), L). => L = [A,B]).
it seems to be ok, but i guess is implementation specific, so it might be a problem.

i would like to hear your comments on this.
maybe other names for 'vmaplist', 'vmaplist_a' ?

-attoparsec-


      ____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile.  Try it now.  http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ

------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...

Re: maplist and friends

by Ulrich Neumerkel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Saturday 19 Apr 2008 02:00:47 Attila Bartha writes:
> i'm experimenting with variations on maplist and friends.
> i would like more control on which arguments of the predicate will be unified with the elements of the lists.

Your vmaplist does not give you more control, but less.  The variables
occurring dynamically at the time of calling vmaplist in Pred are now
local.  For instance, vmaplist cannot describe maplist(=(_), L); a
list with all elements equal.

Admittedly, the higher order style of maplist/2 is not everybody's
turf.  You gave vmaplist(X<10, [1,2,3]) as an example, which
reformulates to maplist(>(10), [1,2,3]).  Here, we have luck, as a
substitute for the original </2 is available that slides the variable
into the last argument.  In general, define an auxiliary predicate
where the last arguments are substituted.  A more lambdaoid notation
would help, but there is no consensus on this - yet.

Your definition cuts choices incorrectly resulting in inconsistent
behaviour: While ?- Xs = [1], maplist(=(1),Xs). suceeds,
?- maplist(=(1),Xs), Xs = [1]. incorrectly fails.  Just remove those
unlucky adornments.

If you insist on finite lists, state must_be(list,L) in the beginning.
Even then the choice cut is useless and costs time and attention.

The exact variable order for term_variables/2 is stated in the manual.

Accelerate the internal list predicates taking their 3rd argument first.

Surprised by you reporting a factor of two in slowdown, I remeasured
times obtaining a factor of 10:

f.pl contains additionally rule p(L) :- maplist(<(0),L). to trigger
specialization - as it would be implicitly the case in a bigger
program.

My .plrc (or pl.ini) contains as first line
:- use_module(library(apply_macros)).
to accelerate maplist.  Also clpfd and DCGs profit significantly from
that line.

g1> pl -O -s f.pl -t halt -g 'time(forall((numlist(1,200,L),between(1,10000,_)), vmaplist(0<X,L))).'
...
%  library(apply_macros) compiled into apply_macros 0.00 sec, 69,416 bytes
...
% /nfs/ahome/ulrich/.plrc compiled 0.03 sec, 602,344 bytes
% f.pl compiled 0.00 sec, 3,536 bytes
% 8,030,408 inferences, 2.70 CPU in 2.71 seconds (100% CPU, 2974225 Lips)
g1> pl -O -s f.pl -t halt -g 'time(forall((numlist(1,200,L),between(1,10000,_)), maplist(<(0),L))).'
...
%  library(apply_macros) compiled into apply_macros 0.00 sec, 69,416 bytes
...
% /nfs/ahome/ulrich/.plrc compiled 0.03 sec, 602,344 bytes
% f.pl compiled 0.00 sec, 3,536 bytes
% 2,010,408 inferences, 0.26 CPU in 0.27 seconds (98% CPU, 7732338 Lips)

------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...

Re: maplist and friends

by Attila Bartha :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

--- On Mon, 4/21/08, Ulrich Neumerkel <ulrich@...> wrote:

> The variables occurring dynamically at the time of calling vmaplist in
> Pred are now local.  For instance, vmaplist cannot describe
> maplist(=(_), L); a list with all elements equal.

the locality of variables is one thing i want from vmaplist.
if i want a free var in Pred to share with all elements of the list, i still have maplist.

> In general, define an auxiliary predicate where the last arguments
> are substituted.  

defining auxiliary predicates is exactly what i want to avoid.

> A more lambdaoid notation would help, but there is no consensus
> on this - yet.

i'm interested in proposals. can you point me to some resources ?
the 2nd argument of vmaplist_a is in fact a kind of lambda.
vmaplist just builds this 'lambda-list' and passes it to vmaplist_a.

> Your definition cuts choices incorrectly resulting in
> inconsistent behaviour

you are right, the cut is useless.

> Surprised by you reporting a factor of two in slowdown, I
> remeasured times obtaining a factor of 10

you are right again. i rerun the tests and i got 3 to 5 time speed drop without optimization and apply_macros.
(looking again on my tests i discovered that vmaplist required 2 x more *inferences* - i think that's why i said half a speed. blunder. )

however, vmaplist can be macroed out just as maplist.

maybe a syntax like in bagof for 'lambda-vars' ?
vmaplist(somepred(^X, a, ^Y, 2), A, B).
then the macro expander can define an aux predicate where the ^-marked vars are moved in the last positions.

-attoparsec-



      ____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile.  Try it now.  http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ

------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...

Re: maplist and friends

by Samer Abdallah :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 21 Apr 2008, at 03:59, Bartha Attila wrote:

> i'm interested in proposals. can you point me to some resources ?
> the 2nd argument of vmaplist_a is in fact a kind of lambda.
> vmaplist just builds this 'lambda-list' and passes it to vmaplist_a.
>

I've been using something like this - it's based on a replacement  
call-like
predicate that accepts a lambda term as the first argument. An example
of a lambda term would be something like:
        ( \(X,Y,Z) :- foo(Z,a), bar(b,X-Y) )
ie, it's a binary term Head :- Body, where Head is an n-ary term
with '\' as the functor, and Body is a goal. It behaves more or less as
if a dummy predicate had been defined
        dummy(X,Y,Z) :-
                foo(Z,a),
                bar(b,X-Y).

I say 'more or less' because if there are free variables in the body,
they must instantiate to a single value in the calling context
        ?- maplist( \(A):-A=B, [a,a,a,a]).
succeeds with B=a while
        ?- maplist( \(A):-A=B, [a,b,a,a]).
fails. However, the body can include an explicit existential
quantification so that, eg
        ?- maplist( \(A):- B^(A=B), [a,b,c,d]).
succeeds leaving B unbound.

Implementation is based on a replacement call/N predicate;
without the obvious bits and without the extra clauses to handle
existential quantification, it looks like this:

        maplist(P,[A|AX]) :- call(P,A), maplist(P,AX).
        maplist(P,[A|AX],[B|BX] :- call(P,A,B), maplist(P,AX,BX).
        % etc.

        call(P,A) :- mkcall(P, \(A), G), call(G).
        call(P,A,B) :- mkcall(P, \(A,B), G), call(G).
        call(P,A,B,C) :- mkcall(P, \(A,B,C), G), call(G).
        % etc.

        mkcall(Head:-Body,Args,Goal) :- copy_term(Head:-Body,Args:-Goal).


- Samer




------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...

Re: maplist and friends

by Ulrich Neumerkel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Monday 21 Apr 2008 12:48:13 Samer Abdallah wrote:
> ...   However, the body can include an explicit existential
> quantification so that, eg
>         ?- maplist( \(A):- B^(A=B), [a,b,c,d]).
> succeeds leaving B unbound.

What about

?- B = a, maplist( \(A):- B^(A=B), [a,b,c,d]).

which should succeed (or produce an error), since the B at the top is
different.  To treat this correctly quite a lot would have to be
reconsidered.  And all this, just to avoid inventing a new name -
which certainlich is cumbersome.

By the same token, I do not see how macro-expansion could be
implemented for this construct in a way similar to maplist.  That is,
without user-visible scope changes of variables.  The same objection
holds for Attila Bartha's vmaplist.

The cleanest way I see (but do not like) is to put most of the lambda
into a string or other ground structure thereby avoiding scoping
problems (and complicating variables with global scope).  The runtime
overheads would be negligible as expansion would usually occur at
compile time.  But the overheads for reading and writing hurt.
Languages with scoping have a pile of restrictions Prolog people do
not like either.  Well, maybe - there is a better way? Qui sait!

------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...

Re: maplist and friends

by Samer Abdallah :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 21 Apr 2008, at 14:33, Ulrich Neumerkel wrote:
> On Monday 21 Apr 2008 12:48:13 Samer Abdallah wrote:
>> ...   However, the body can include an explicit existential
>> quantification so that, eg
>>         ?- maplist( \(A):- B^(A=B), [a,b,c,d]).
>> succeeds leaving B unbound.
>
> What about
>
> ?- B = a, maplist( \(A):- B^(A=B), [a,b,c,d]).

As it stands, my code would see this as
        maplist( \(A) :- a^(A=a), [a,b,c,d])
It would ignore the existential quantification since it
contains no variables, and therefor fail overall since some
elements are not 'a'. If I was being more careful I would
probably make any ground term in the existential
quantification produce an error. Overall, it's not a lot of
code, though I will admit that the existential variable
handling code isn't pretty since it needs to manipulate
sets of uninstantiated variables.

>
> which should succeed (or produce an error), since the B at the top is
I'm not sure why you would expect it to succeed - perhaps
you are reading the existential quantification differently from
me? My interpretation is that the existential quantification
is to make it behave exactly like an auxiliary predicate defined
in the usual way:
        aux(A) :- A=B
which has the implicit quantification, ie, it means
        (exists B . A=B)  => aux(A)
> different.  To treat this correctly quite a lot would have to be
> reconsidered.  And all this, just to avoid inventing a new name -
> which certainlich is cumbersome.
>
> By the same token, I do not see how macro-expansion could be
> implemented for this construct in a way similar to maplist.  That is,
Fair enough - I don't really know anything about macro expansion -
my version runs in a meta-interpreter so it's dog slow whatever
i do :)


> without user-visible scope changes of variables.  The same objection
> holds for Attila Bartha's vmaplist.
>
> The cleanest way I see (but do not like) is to put most of the lambda
> into a string or other ground structure thereby avoiding scoping
This addresses the heart of the problem which is that a lambda
expression is a term that needs to refer to variables; that is,  
variables
are used as part of the object language - but in this case they need to
be 'lambda variables', not Prolog variables; that is, they need to be  
ground
objects which denote 'variables in the language of lambda expressions'.
The fact that Prolog does such a good job of being its own meta-language
makes it easy to get into the sort of mess where Prolog variables are
used as stand-ins for variables which strictly belong to a different
level and hence we need to use all sorts of non-logical Prolog code to
manipulate them. So one option would be to use a certain set of ground
terms to denote variables, eg a unary operator/functor like ?/1:
        maplist(  \(?x) :- ?y ^(?x = ?y), [a,b,c,d]).
But then it all starts to get a bit heavy and maybe it would be better
just to define an auxiliary predicate after all...

Samer

> problems (and complicating variables with global scope).  The runtime
> overheads would be negligible as expansion would usually occur at
> compile time.  But the overheads for reading and writing hurt.
> Languages with scoping have a pile of restrictions Prolog people do
> not like either.  Well, maybe - there is a better way? Qui sait!


------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...

Re: maplist and friends

by Ulrich Neumerkel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Monday 21 Apr 2008 16:06:27 Samer Abdallah wrote:

> On 21 Apr 2008, at 14:33, Ulrich Neumerkel wrote:
> > On Monday 21 Apr 2008 12:48:13 Samer Abdallah wrote:
> >> ...   However, the body can include an explicit existential
> >> quantification so that, eg
> >>         ?- maplist( \(A):- B^(A=B), [a,b,c,d]).
> >> succeeds leaving B unbound.
> >
> > What about
> >
> > ?- B = a, maplist( \(A):- B^(A=B), [a,b,c,d]).
> ...
> > which should succeed (or produce an error), since the B at the top is
> I'm not sure why you would expect it to succeed - perhaps
> you are reading the existential quantification differently from
> me? My interpretation is that the existential quantification
> is to make it behave exactly like an auxiliary predicate defined
> in the usual way:
>         aux(A) :- A=B
> which has the implicit quantification, ie, it means
>         (exists B . A=B)  => aux(A)

Yes, so the B outside in B = a must be something different, entirely
unrelated to the quantified B.  It is the same as renaming the
internal B to B1.

Remark that you will succed for

?- maplist( \(A):- B^(A=B), [a,b,c,d]), B = a

as well, which would be consistent with the success of

?- B = a, maplist( \(A):- B^(A=B), [a,b,c,d]).

As we have here a pure program the conjunction G, H should be the same
as H, G.  You might have issues about termination and similar to
settle, but otherwise there cannot be any differences.

The most sensible would be some static checking, but there the
difficulties start...

Note that ensuring B being a variable is not sufficient, as it may share
with other variables in conflicting scope.

------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...

Re: maplist and friends

by Kuniaki Mukai :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


(Sorry for my poor English.)

Interesting thread !

For years, I have written several versions of predicate eval
including lambda calculus on top of SWI-Prolog for fun.  In order to
keep theoretical soundness of lambda ( beta ) calculus, the eval
refreshes bound variables for every application !

Here are several sample calls for the eval predicate,
where \ for lambda abstraction,   \\ for Prolog call,
and  @ for  application.

?- eval((x\x)@ (y\y), V).
V =  y\y
?- eval(((X\X)@ (Y\Y))@ hello, V).
V =  hello
?- eval([x,y]\[x,y])@1@2, V).
V = [1, 2]
?- maplist(x\ [x], [a,b,c], V).
V= [[a], [b], [c]]
?- maplist(x\y\(y @ x), [a,b,c], [x\[x], x\[x,x], x\[x,x,x]], V)
V =  [[a], [b, b], [c, c, c]]
?- maplist([x,y,z]\\ append(x,z,y), [[a],[b]], [[a,b,c], [b,a,c]], V).
V = [[b, c], [a, c]].

If interested, you can find many more samples at the page
http://web.sfc.keio.ac.jp/~mukai/mathcgi/fpop-sample.html,
which was created by a simple script written in SWI-Prolog
using the eval

I should say the current code of the eval predicate is, of course,
very slow.  However, I feel lambda notation in Prolog is handy
and useful for daily use of Prolog where efficiency
does not matter.

Learning about 'apply_macro' library in this thread, now I think the
library can be extended to treat these lambda expressions as macros.
I think so because at least for my purpose,  lambda expressions
are just a handy macro which is easily rewritten by hand
into the standard Prolog in a straightforward way.

Kuniaki Mukai


On 2008/04/22, at 8:40, Ulrich Neumerkel wrote:

> On Monday 21 Apr 2008 16:06:27 Samer Abdallah wrote:
>> On 21 Apr 2008, at 14:33, Ulrich Neumerkel wrote:
>>> On Monday 21 Apr 2008 12:48:13 Samer Abdallah wrote:
>>>> ...   However, the body can include an explicit existential
>>>> quantification so that, eg
>>>>        ?- maplist( \(A):- B^(A=B), [a,b,c,d]).
>>>> succeeds leaving B unbound.
>>>
>>> What about
>>>
>>> ?- B = a, maplist( \(A):- B^(A=B), [a,b,c,d]).
>> ...
>>> which should succeed (or produce an error), since the B at the top  
>>> is
>> I'm not sure why you would expect it to succeed - perhaps
>> you are reading the existential quantification differently from
>> me? My interpretation is that the existential quantification
>> is to make it behave exactly like an auxiliary predicate defined
>> in the usual way:
>>        aux(A) :- A=B
>> which has the implicit quantification, ie, it means
>>        (exists B . A=B)  => aux(A)
>
> Yes, so the B outside in B = a must be something different, entirely
> unrelated to the quantified B.  It is the same as renaming the
> internal B to B1.
>
> Remark that you will succed for
>
> ?- maplist( \(A):- B^(A=B), [a,b,c,d]), B = a
>
> as well, which would be consistent with the success of
>
> ?- B = a, maplist( \(A):- B^(A=B), [a,b,c,d]).
>
> As we have here a pure program the conjunction G, H should be the same
> as H, G.  You might have issues about termination and similar to
> settle, but otherwise there cannot be any differences.
>
> The most sensible would be some static checking, but there the
> difficulties start...
>
> Note that ensuring B being a variable is not sufficient, as it may  
> share
> with other variables in conflicting scope.
>
> ------------
> For further info, please visit http://www.swi-prolog.org/
>
> To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-
> mail>"
> in its body to majordomo@...

------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...