Currying blocks, is it possible?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Currying blocks, is it possible?

Fernando Rodríguez
Hi,

I have a collection of 'Person' objects that I want to sort using
different criteria: firstname, dateOfBirth, etc...

I was planning to use a curried sort block hat can be specialized for
each case. Something like this:

curry := [:query| ^[:a :b| (a perform: query) < (b perform: query)]]

This evaluates fine and I don't get any errors. However, when I try to
use it:

ss := SortedCollection sortBlock: (curry value: #firstname).

I get a weird error: "Cannot return a Block closure to expired context
or across processes".

What on Earth does it mean? O:-)  Can you use curried blocks in
Smalltalk? Is there any limitation in St's blocks that I am unaware of?
I thought they were like lisp/scheme closures...

Thanks.

PS I'm using Dolphin 5.1, although it doesn't work with Squeak either.


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Udo Schneider
Fernando wrote:
> curry := [:query| ^[:a :b| (a perform: query) < (b perform: query)]]
> [...]
> I get a weird error: "Cannot return a Block closure to expired context
> or across processes".
> [...]
> What on Earth does it mean? O:-)  Can you use curried blocks in
> Smalltalk? Is there any limitation in St's blocks that I am unaware of?
> I thought they were like lisp/scheme closures...
I think your problem here is the carret "^". This tells ST to return
from the method (context) in which the block was used. If you assign the
block to a var and send it #value: later on the block get's executed in
a BlockContext. And a block context cannot return from a method ....


Just remove the carret and everything should work.

CU,

Udo


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Hans-Martin Mosner
In reply to this post by Fernando Rodríguez
"Fernando" <[hidden email]> wrote:
> Hi,
>
> I have a collection of 'Person' objects that I want to sort using
> different criteria: firstname, dateOfBirth, etc...
>
> I was planning to use a curried sort block hat can be specialized for
> each case. Something like this:
>
> curry := [:query| ^[:a :b| (a perform: query) < (b perform: query)]]

Just omit the caret.
You use it to return from a method invocation. But for blocks, the
return value is always the value of the last expression in the block's
statement sequence.

Cheers,
Hans-Martin


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Fernando Rodríguez
Hi Hans,

There's still one thing that I don't understand.  Consider this new
version of the 'curry' block:

curry2 := [:query| [:a :b| (a query) < (b query)]].

When I evaluate
c := curry2 value: #firstname.

I expected a block equivalent to the one below, to be returned:
[:a :b| (a firstname) < (b firstname)]

That's not the case and if I try to use c (as a sort block for an
SortedCollection of classes thatunderstand the #firstname message), I
get a DNU error, complaining that 'Person does not understand query'.

What am I missing? O:-)

Thanks


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Udo Schneider
Fernando wrote:
> There's still one thing that I don't understand.  Consider this new
> version of the 'curry' block:
>
> curry2 := [:query| [:a :b| (a query) < (b query)]].

Using this block you're sending the message #query to a and b. Although
you have a var of a same name not every occurence of the string 'query'
will be replaced with the var of the dame name.

> When I evaluate
> c := curry2 value: #firstname.
>
> I expected a block equivalent to the one below, to be returned:
> [:a :b| (a firstname) < (b firstname)]
What you want to a and b to do is to perform the message encoded in 'query'.

So the resulting block would be:
curry2 := [ :query | [ :a :b | (a perform: query) < (b perform: query) ]

> That's not the case and if I try to use c (as a sort block for an
> SortedCollection of classes thatunderstand the #firstname message), I
> get a DNU error, complaining that 'Person does not understand query'.
You'll get a DNU because the message #query is sent to a and b. Just
using the same name for a message and a var doesn't mean that each
occurence of the message is replaced with the var content. If this would
be the case just try to imagine if I do something like
c := curry value: Smalltalk

:-)

Hope this helps,

Udo


>
> What am I missing? O:-)
>
> Thanks
>


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Reinout Heeck-3
In reply to this post by Fernando Rodríguez
Fernando wrote:

> Hi Hans,
>
> There's still one thing that I don't understand.  Consider this new
> version of the 'curry' block:
>
> curry2 := [:query| [:a :b| (a query) < (b query)]].
>
> When I evaluate
> c := curry2 value: #firstname.
>
> I expected a block equivalent to the one below, to be returned:
> [:a :b| (a firstname) < (b firstname)]

But you get
   [:a :b | a query < b query ]

Note that curry2 has two different uses of 'query',
once as a named block argument (that is never used) and
twice as a unary message sent to a and b.

You will need to use #perform: inside your curry2 above (as in
   a perform: query
or use another technique like passing in blocks instead of the message
name along these lines:    ( untested :-)

smallerThan := [:aspect |
               [:a :b | (aspect value: a) < (aspect value: b)] ].

byFirstName := [:obj | obj firstName ].


sortBlock := smallerThan value: byFirstname

this should result in sortBlock being equivalent to
[ :a :b |
         ([:obj | obj firstName] value: a) <
         ([:obj | obj firstName] value: b)
]





See also these blog entries by ExtraTravis for additional tweaks:

1) using a sort object instead of a sort block:
http://www.cincomsmalltalk.com/userblogs/travis/blogView?showComments=true&entry=3275167671

2) making Symbol polymorphic with a unary block:
http://www.cincomsmalltalk.com/userblogs/travis/blogView?showComments=true&entry=3264534180


Perhaps you'll find this page instructive too:
 
http://wiki.cs.uiuc.edu/VisualWorks/How+to+get+rid+of+Objects+in+Smalltalk




Success!

Reinout
-------



>
> That's not the case and if I try to use c (as a sort block for an
> SortedCollection of classes thatunderstand the #firstname message), I
> get a DNU error, complaining that 'Person does not understand query'.
>
> What am I missing? O:-)
>
> Thanks
>


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

David Simmons-2
In reply to this post by Udo Schneider
I made a c.l.s. post on this a few years back describing how to create
currying (agent) "valuables" (of which blocks are just a special case).

It is very easy to implement if you realize a few things.

a) We want a wrapper that will eventually return a computed value when all
the input arguments are available to the wrappered object.

b) That will return the wrapper until all the input arguments are available.

c) The wrapper will conform to a dynamic valuable protocol that retains
history of previously applied/accumulated values.

Given that we can create a class called <Currier>

We can give it members called:

   arguments, argc_limit, valuable_target

We can give it a var-arg method that supports the root name #value. Or in
classic (non-S#) implementations we can simply provide a series of #value...
method implementations up to our maximum desired arity (argc invocation
form).

We then provide a constructor/initializer (#new variant or equivalent) that
will record the <valuable_target>, set/compute the <argc_limit>, and
initialize the <arguments> container mechanism.

As various #value... forms are invoked the previously accumulated
<arguments> container in combination with the supplied #value... arguments
are checked against the <argc_limit>. When the limit is reached, the
<valuable_target> is sent the #value... arity message that corresponds to
the <argc_limit> with the set of accumulated arguments + (any optional extra
arguments that may have been supplied (S#)). If the limit has not been
reached then the <Currier>  wrapper instance is returned.

Since Smalltalk uses ad-hoc polymorphism, and both the <Currier> class and
the wrappered <valuable_target> support the "valuable" protocol we can
substitute one for the other at any time.

-- Dave S.

"Udo Schneider" <[hidden email]> wrote in message
news:421b403c$[hidden email]...

> Fernando wrote:
> > There's still one thing that I don't understand.  Consider this new
> > version of the 'curry' block:
> >
> > curry2 := [:query| [:a :b| (a query) < (b query)]].
>
> Using this block you're sending the message #query to a and b. Although
> you have a var of a same name not every occurence of the string 'query'
> will be replaced with the var of the dame name.
>
> > When I evaluate
> > c := curry2 value: #firstname.
> >
> > I expected a block equivalent to the one below, to be returned:
> > [:a :b| (a firstname) < (b firstname)]
> What you want to a and b to do is to perform the message encoded in
'query'.

>
> So the resulting block would be:
> curry2 := [ :query | [ :a :b | (a perform: query) < (b perform: query) ]
>
> > That's not the case and if I try to use c (as a sort block for an
> > SortedCollection of classes thatunderstand the #firstname message), I
> > get a DNU error, complaining that 'Person does not understand query'.
> You'll get a DNU because the message #query is sent to a and b. Just
> using the same name for a message and a var doesn't mean that each
> occurence of the message is replaced with the var content. If this would
> be the case just try to imagine if I do something like
> c := curry value: Smalltalk
>
> :-)
>
> Hope this helps,
>
> Udo
>
>
> >
> > What am I missing? O:-)
> >
> > Thanks
> >


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Fernando Rodríguez
On Fri, 25 Feb 2005 11:43:37 -0800, "David Simmons"
<[hidden email]> wrote:

>I made a c.l.s. post on this a few years back describing how to create
>currying (agent) "valuables" (of which blocks are just a special case).
[snip]

Could you provide an example of such a class? O:-)

Thanks


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

David Simmons-2
Here is a piece of the discussion from the Google archives.

May 16 2004, 9:34 pm
Jun 2 2004, 6:22 pm

I will try and find the original post and the sample class next week.

http://groups-beta.google.com/group/comp.lang.smalltalk/browse_thread/thread/230e870d73cb9e42/7bc66f6754193927?q=currying+valuable+dave+smallscript&_done=%2Fgroup%2Fcomp.lang.smalltalk%2Fsearch%3Fgroup%3Dcomp.lang.smalltalk%26q%3Dcurrying+valuable+dave+smallscript%26qt_g%3D1%26&_doneTitle=Back+to+Search&&d#7bc66f6754193927

-- Dave S.

"Fernando" <[hidden email]> wrote in message
news:[hidden email]...

> On Fri, 25 Feb 2005 11:43:37 -0800, "David Simmons"
> <[hidden email]> wrote:
>
> >I made a c.l.s. post on this a few years back describing how to create
> >currying (agent) "valuables" (of which blocks are just a special case).
> [snip]
>
> Could you provide an example of such a class? O:-)
>
> Thanks
>


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Chris Uppal-3
In reply to this post by David Simmons-2
David Simmons wrote:

> I made a c.l.s. post on this a few years back describing how to create
> currying (agent) "valuables" (of which blocks are just a special case).

I remember that (if not too clearly), and I meant to reply at the time.

There's a potential singularity in your scheme when what started out as an
<N-adicValuable> (for some N) has been supplied with N arguments (via the
currying mechanism) -- is the result a <niladicValuable> or an ordinary value
(a String, say, or a Dilpodocus) ?  Also, sending #value (providing /zero/
further parameters) to a curried <N-adicValuable> should, to follow the
currying pattern, return an <(N-0)-adicValuable>, i.e. #value should be an
identity transformation.  Combining the two cases means that providing N
parameter values to an <N-adicCurriedValuable> should produce a
<niladicCurriedValuable> from which it is then impossible to extract a useful
#value.  The only way out seems to be for the currying scheme to have a
singularity around 0, where it "magically" stops following the regular rules.

That kind of nasty semantic glitch would probably be acceptable in a
special-purpose implementation of a <curriedValuable> protocol  (perhaps you
could send #curried to a Block to obtain a custom object that implemented the
curried variant of the <*Valuable> stuff).  Which is how your discussion here
(not quoted) sounds as if you are seeing it.  But, if I remember correctly, you
were originally proposing for that semantics to be built-in to S#'s native
blocks (but perhaps I misunderstood ?).

(There's also the minor technical question: should

    ([:a :b | a ** b] curried) value: 3

answer the equivalent of:

    [:x | x ** 3]

or:

    [:x | 3 ** x]

But that can be answered by fiat, and perhaps by providing a (logically
unnecessary) extension to the <valuable> protocol.)

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

David Simmons-2
Hi Chris,

You're right that there could definitely be a singularity. My assumption had
been that the model was basically just a temporally deferred #value...
message.

Meaning that whenever the supplied arity condition was met, the valuable
receiver would be invoked exactly as if all the arguments had been supplied
in one temporal unit.

(does that sentence above make sense ^?)

Given that assertion, the answer becomes:

#value (arity 0) wrappered valuables are triggered upon the 1st valuation
received (without regard to argc)

In all other cases, sending #value to Currier instance is equivalent to
sending #yourself.

Once the "trigger" event occurs, the returned value is the result returned
by the inner valuable.

--

The question of what to do with any extra arguments supplied could be
handled with a currier policy setting. In the case of S# it supports var-arg
facilities and it defines the ability to invoke valuable (and especially a
block) with either more or less args than its original arity declaration. If
more are supplied they become optional var-args, if less then missing
arguments are filled with <nil>. The currier would prevent the latter
scenario from ever occuring unless the currier's arity was set to less than
the declared arity of the valuable.

-- Dave

"Chris Uppal" <[hidden email]> wrote in message
news:4220506d$0$38038$[hidden email]...

> David Simmons wrote:
>
> > I made a c.l.s. post on this a few years back describing how to create
> > currying (agent) "valuables" (of which blocks are just a special case).
>
> I remember that (if not too clearly), and I meant to reply at the time.
>
> There's a potential singularity in your scheme when what started out as an
> <N-adicValuable> (for some N) has been supplied with N arguments (via the
> currying mechanism) -- is the result a <niladicValuable> or an ordinary
value
> (a String, say, or a Dilpodocus) ?  Also, sending #value (providing /zero/
> further parameters) to a curried <N-adicValuable> should, to follow the
> currying pattern, return an <(N-0)-adicValuable>, i.e. #value should be an
> identity transformation.  Combining the two cases means that providing N
> parameter values to an <N-adicCurriedValuable> should produce a
> <niladicCurriedValuable> from which it is then impossible to extract a
useful
> #value.  The only way out seems to be for the currying scheme to have a
> singularity around 0, where it "magically" stops following the regular
rules.
>
> That kind of nasty semantic glitch would probably be acceptable in a
> special-purpose implementation of a <curriedValuable> protocol  (perhaps
you
> could send #curried to a Block to obtain a custom object that implemented
the
> curried variant of the <*Valuable> stuff).  Which is how your discussion
here
> (not quoted) sounds as if you are seeing it.  But, if I remember
correctly, you

> were originally proposing for that semantics to be built-in to S#'s native
> blocks (but perhaps I misunderstood ?).
>
> (There's also the minor technical question: should
>
>     ([:a :b | a ** b] curried) value: 3
>
> answer the equivalent of:
>
>     [:x | x ** 3]
>
> or:
>
>     [:x | 3 ** x]
>
> But that can be answered by fiat, and perhaps by providing a (logically
> unnecessary) extension to the <valuable> protocol.)
>
>     -- chris
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Chris Uppal-3
David,
>
> You're right that there could definitely be a singularity. My assumption
> had been that the model was basically just a temporally deferred #value...
> message.

Yes, if you picture it like that, then the singularity doesn't feel nearly so
irregular.

I'd been picturing it as a mapping:

    <N-adicValuable> -> <M-adicValuable>    (m <= N)

in which terms the singularity looks pretty obnoxious ;-)

BTW, I've only just realised that all this can be thought of as mere syntactic
sugar (or maybe I mean semantic sugar) for nesting blocks:

    v3 := [:a :b :c | a ** b ** c].
    v2 := [:a :b | v3 value: a value: b value: 999].

probably that's been obvious to everyone else all along...

     -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Currying blocks, is it possible?

Fernando Rodríguez
In reply to this post by David Simmons-2
On Fri, 25 Feb 2005 16:25:58 -0800, "David Simmons"
<[hidden email]> wrote:

>Here is a piece of the discussion from the Google archives.
>
>May 16 2004, 9:34 pm
>Jun 2 2004, 6:22 pm
>
>I will try and find the original post and the sample class next week.

Thanks, I tried but couldn't find it on google.