Higher Order Function Question

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Higher Order Function Question

Håkan Stenholm-3
 >Thank you Haken,
 >
 >but the issue is not "apply" - I was only using that to experiment
 >-- the issue is "map" or "filter" which, apparently, will only
 >accept {attr, isPk} and not attr:isPk (which I am told is "more
 >elegant" and certainly more efficient).
 >
I think there has been slight missunderstanding here, apply(M,F,A) is
the old classic version of how to call a fun, modern erlang supports
funs to be called as F1(A) or M:F2(A) where  F1 is a fun as defined
previously:
 > Fun = fun(Arg1, Arg2 ....) -> ... end  % anynomouse fun
 > Fun = fun FunctionName/Arity           % local fun in current file
 > Fun = {Module, FunctionName}           % any exported function can be
used
 >
but it is also possible for M and F2 to be arbitrary atoms i.e. this can
also be done:

% define this function
my_apply(M,F2,A) -> M:F2(A).
% this can be called as
my_apply(lists,append,[[1,2],[3,4]])
% and result in [1,2,3,4]

But "Fun = lists:append," (or similar construct) is not a legal way to
define a fun. The F1(A) and M:F2(A) syntax is prefered to the
apply(M,F,A) syntax because it's more efficent in most cases (see the
"performance hints" link on the R8B documentation index.html page).

 >map and filter will accept:
 >
 >lists:map(fun(Arg) -> attr:varName(Arg) end,
 >rel:attrList(rel:findNamed(ng,"Member"))).
 >
 >but this is quite ugly looking code (albeit probably more efficient
 >than {attr, isPk}...
 >
 >>Alex
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: text/enriched
Size: 1482 bytes
Desc: not available
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20020525/ad5fd375/attachment.bin>

Reply | Threaded
Open this post in threaded view
|

Higher Order Function Question

Alex Peake
Perhaps I could go back a step, to my orginal problem -- obviously not
stated clearly:

I was struggling to use "filter" with the "complement of" a predicate (in my
case not attr:isPk).

In explaining the problem, it came out that in my code I wrote things like:

lists:map({attr,varName}, rel:attrList(rel:findNamed(ng,"Member"))).

I was informed that this is "not elegant" and "inefficient" because it "is
the old classic version of how to call a fun".

So I asked for how to do this the "modern Erlang" way. I pointed out that:

lists:map(fun(Arg) -> attr:varName(Arg) end,
rel:attrList(rel:findNamed(ng,"Member"))).

is more efficient, but as programmer reading this, I find the fun...end part
makes the intent less clear.


Similarly:

Fn = fun attr:varName/1,
lists:map(Fn, rel:attrList(rel:findNamed(ng,"Member"))).

I also find cluttered.

Richard Carlsson suggested the very elegant approach using list
comprehensions:

[attr:varName(Attr) || Attr <- rel:findNamed(ng,"Member")]

This is what I am using.


None-the-less, I am learning Erlang and am interested in the "moderen
Erlang" way to use map, filter. Perhaps the answer is list comprehensions?


Alex



BTW, my solution to the filter with complement of a predicate, thanks to
Richard, is:

[attr:varName(Attr) || Attr <- rel:findNamed(ng,"Member"), not
attr:isPk(Attr)]




-----Original Message-----
From: Hakan Stenholm [mailto:hakan.stenholm]
Sent: Saturday, May 25, 2002 6:18 AM
To: erlang-questions
Cc: apeake
Subject: RE: Higher Order Function Question


>Thank you Haken,
>
>but the issue is not "apply" - I was only using that to experiment
>-- the issue is "map" or "filter" which, apparently, will only
>accept {attr, isPk} and not attr:isPk (which I am told is "more
>elegant" and certainly more efficient).
>
I think there has been slight missunderstanding here, apply(M,F,A) is the
old classic version of how to call a fun, modern erlang supports funs to be
called as F1(A) or M:F2(A) where F1 is a fun as defined previously:
> Fun = fun(Arg1, Arg2 ....) -> ... end % anynomouse fun
> Fun = fun FunctionName/Arity % local fun in current file
> Fun = {Module, FunctionName} % any exported function can be used
>
but it is also possible for M and F2 to be arbitrary atoms i.e. this can
also be done:

% define this function
my_apply(M,F2,A) -> M:F2(A).
% this can be called as
my_apply(lists,append,[[1,2],[3,4]])
% and result in [1,2,3,4]

But "Fun = lists:append," (or similar construct) is not a legal way to
define a fun. The F1(A) and M:F2(A) syntax is prefered to the apply(M,F,A)
syntax because it's more efficent in most cases (see the "performance hints"
link on the R8B documentation index.html page).

>map and filter will accept:
>
>lists:map(fun(Arg) -> attr:varName(Arg) end,
>rel:attrList(rel:findNamed(ng,"Member"))).
>
>but this is quite ugly looking code (albeit probably more efficient >than
{attr, isPk}...
>
>>Alex




Reply | Threaded
Open this post in threaded view
|

Higher Order Function Question

Håkan Stenholm-3

On l?rdag, maj 25, 2002, at 06:08 , Alex Peake wrote:

> Perhaps I could go back a step, to my orginal problem -- obviously not
> stated clearly:
>
> I was struggling to use "filter" with the "complement of" a predicate
> (in my
> case not attr:isPk).
>
> In explaining the problem, it came out that in my code I wrote things
> like:
>
> lists:map({attr,varName}, rel:attrList(rel:findNamed(ng,"Member"))).
>
> I was informed that this is "not elegant" and "inefficient" because it
> "is
> the old classic version of how to call a fun".
>
> So I asked for how to do this the "modern Erlang" way. I pointed out
> that:
>
> lists:map(fun(Arg) -> attr:varName(Arg) end,
> rel:attrList(rel:findNamed(ng,"Member"))).
>
> is more efficient, but as programmer reading this, I find the fun...end
> part
> makes the intent less clear.
>
>
> Similarly:
>
> Fn = fun attr:varName/1,
> lists:map(Fn, rel:attrList(rel:findNamed(ng,"Member"))).
>
> I also find cluttered.
>
> Richard Carlsson suggested the very elegant approach using list
> comprehensions:
>
> [attr:varName(Attr) || Attr <- rel:findNamed(ng,"Member")]
>
> This is what I am using.
>
>
> None-the-less, I am learning Erlang and am interested in the "moderen
> Erlang" way to use map, filter. Perhaps the answer is list
> comprehensions?
>
>
I would say yes, list comprehension is very elegant for filters (and
generators).  I don't think I ever used lists:filter - I usally use
lists:foldl (if map and foreach can't be used), I like foldl because
it's very flexible and used to be faster than list comprehension
(R5-6 ?).



Reply | Threaded
Open this post in threaded view
|

Higher Order Function Question

Richard Carlsson-4
In reply to this post by Alex Peake

On Sat, 25 May 2002, Alex Peake wrote:

> I was struggling to use "filter" with the "complement of" a predicate (in my
> case not attr:isPk).
>
> In explaining the problem, it came out that in my code I wrote things like:
>
> lists:map({attr,varName}, rel:attrList(rel:findNamed(ng,"Member"))).
>
> I was informed that this is "not elegant" and "inefficient" because it "is
> the old classic version of how to call a fun".

In the bad old days, there were no lambda closures at all in Erlang, and
this 2-tuple thing was added as a kind of simple poor man's lambda. But
things have improved since then, and the ability of 'apply' to interpret
2-tuples as function values is really something that is best forgotten.
Really.

> lists:map(fun(Arg) -> attr:varName(Arg) end,
> rel:attrList(rel:findNamed(ng,"Member"))).
>
> is more efficient, but as programmer reading this, I find the
> fun...end part makes the intent less clear.

I'd claim the opposite, in fact. First, the "fun (...) -> ... end"
clearly shows what the operation to be passed to "map" is. Second, the
call "attr:varName(...)" makes it apparent that we are calling a certain
function (with a certain arity) in a certain module, and what the
arguments to that function will be. Of course it requires a few more
characters to type, but as a programming pattern it is both cleaner and
more powerful.

If the function was a local one (in the same module), you could write

        lists:map(fun varName/1, MyList)

but there is no notation "fun M:F/A" for functions in other modules,
because of the way inter-module ("remote") calls work with dynamic code
replacement in Erlang.

List comprehensions are of course very elegant, but only work for
operations that are combinations of map/filter.


Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://www.csd.uu.se/~richardc/
 "Having users is like optimization: the wise course is to delay it."
   -- Paul Graham




Reply | Threaded
Open this post in threaded view
|

Higher Order Function Question

Fredrik Linder-2
> but there is no notation "fun M:F/A" for functions in other modules,
> because of the way inter-module ("remote") calls work with dynamic code
> replacement in Erlang.

You're right. At least I forgot that the M: part isn't supported. :-)

But wouldn't it be nice to have that syntax though. (Could be syntactical
suger for {M, F}) but I guess that would remove the /A check, if there is
one)

/Fredrik



Reply | Threaded
Open this post in threaded view
|

Higher Order Function Question

Richard Carlsson-4

On Mon, 27 May 2002, Fredrik Linder wrote:

> > but there is no notation "fun M:F/A" for functions in other modules,
>
> But wouldn't it be nice to have that syntax though. (Could be
> syntactical suger for {M, F}) but I guess that would remove the /A
> check, if there is one)

It has been suggested several times before, but is probably not a good
idea, because of the difference between a fun and a remote call. A fun
means "exactly the specified code, nothing else" while a remote-call
means "whatever code is called M:F/A at this moment". There are several
technical complications because of this, which could give a "fun M:F/A"
some rather unexpected behaviour - not a good thing in Erlang.

        /Richard


Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://www.csd.uu.se/~richardc/
 "Having users is like optimization: the wise course is to delay it."
   -- Paul Graham