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. |
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 |
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 |
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 |
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 > |
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 > |
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 > > 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 > > |
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 |
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 > |
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 |
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 > (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 > > > |
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 |
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. |
Free forum by Nabble | Edit this page |