BlockClosure

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

BlockClosure

main
Hello fellow Pharoians (?) from a lonely Swede.

I just found out about Pharo (and Smalltalk) two days ago and I'm already
loving it :)
However, there is a behavior I would like to change, or be enlightened about
how it could be done.

As I understand it (bear with me) BlockClosure from Kernel-Methods does not
understand (by default?) how to respond to an "anonymous object" (no message
name).

Is there any way this could be implemented? I'll post an example soon
(I currently use both Pharo 7 and 8)

If I write the following:

[:x | x + 1] value: 3

and evaluate it, I get the expected result, which is 4.

That's nice.

What I would really like is to be able to just send 3 to BlockClosure and
make it repond as above.

Like this:

[:x | x + 1] 3

or like this:

3 [:x | x + 1]

Would this be possible?

-----------------------

Also as a bonus, would it be possible to use this for "function
composition", "Block composition" or similar?

Example of composition:

[ :f :g | [ :x | f value: (g value: x) ] ]

I could use this construct like this for example:

(([ :f :g | [ :x | f value: (g value: x) ] ])
value: [:x | x + 1]
value: [:x | x - 1])
value: 5

But… It's a bit wordy.

What I would like to be able to do (essentialy remove "value:"):

(([ :f :g | [ :x | f (g x) ] ])
[:x | x + 1]
[:x | x - 1])
5.

Or in one line:
(([ :f :g | [ :x | f (g x) ] ]) [:x | x + 1] [:x | x - 1]) 5.

While this might seem obscure, I would really find it useful.

Can it be done?

Thanks in advance



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Systems Architect,
Åkerströms
Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

Esteban A. Maringolo
There's no way you could use an integer (or any  number) as a selector.

So what you can do if you want to avoid using the "wordy" #value: selector is to implement your own selector in BlockClosure.

It could be a #v: selector (so it is still a keyword selector) or a symbol such as #<< that ends up calling #value:, but keep in mind that if you use a symbol you cannot extend it to have more than one parameter.

Regards,



El mié., 23 de octubre de 2019 09:22, main <[hidden email]> escribió:
Hello fellow Pharoians (?) from a lonely Swede.

I just found out about Pharo (and Smalltalk) two days ago and I'm already
loving it :)
However, there is a behavior I would like to change, or be enlightened about
how it could be done.

As I understand it (bear with me) BlockClosure from Kernel-Methods does not
understand (by default?) how to respond to an "anonymous object" (no message
name).

Is there any way this could be implemented? I'll post an example soon
(I currently use both Pharo 7 and 8)

If I write the following:

[:x | x + 1] value: 3

and evaluate it, I get the expected result, which is 4.

That's nice.

What I would really like is to be able to just send 3 to BlockClosure and
make it repond as above.

Like this:

[:x | x + 1] 3

or like this:

3 [:x | x + 1]

Would this be possible?

-----------------------

Also as a bonus, would it be possible to use this for "function
composition", "Block composition" or similar?

Example of composition:

[ :f :g | [ :x | f value: (g value: x) ] ]

I could use this construct like this for example:

(([ :f :g | [ :x | f value: (g value: x) ] ])
value: [:x | x + 1]
value: [:x | x - 1])
value: 5

But… It's a bit wordy.

What I would like to be able to do (essentialy remove "value:"):

(([ :f :g | [ :x | f (g x) ] ])
[:x | x + 1]
[:x | x - 1])
5.

Or in one line:
(([ :f :g | [ :x | f (g x) ] ]) [:x | x + 1] [:x | x - 1]) 5.

While this might seem obscure, I would really find it useful.

Can it be done?

Thanks in advance



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

hogoww
In reply to this post by main
Hi,


The first part could be done, but with limitations.

- you won't be able to value it with anything but variables names

- those variables cannot have the same name as a method of BlockClosure

- I don't think this can be implemented by default in Pharo, as it is
kinda "dangerous"

- might be unreliable, i don't know how stable Context is. ( For my own
experiments, I have some problem with P7, but my stuff work fine on P8)


You'd have to implement something like:

BlockClosure >> DoesNotUnderstand: aMessage
     valueOfSelector := self outerContext at: aMessage selector
ifAbsent:[ ^ super doesNotUnderstand "The variable isn't found in the
context, so it's a real DNU "].

     self valueWithArguments: valueOfSelector asArray "allows us to have
several arguments"


So if you did:

aVariable := 3.

[:x | x + 3] aVariable.


The block would say it didn't understand the message aVariable, and
you'd perform it in the doesNotUnderstand hook you just override.

I guess it'd be something similar for the second part of your question,
but i'm pretty sure it becomes unreadable rather quickly ˆˆ


PS: I didn't test this, but it's something in that spirit.

the context access might not be outerContext.

Pierre.


On 23/10/2019 09:22, main wrote:

> Hello fellow Pharoians (?) from a lonely Swede.
>
> I just found out about Pharo (and Smalltalk) two days ago and I'm already
> loving it :)
> However, there is a behavior I would like to change, or be enlightened about
> how it could be done.
>
> As I understand it (bear with me) BlockClosure from Kernel-Methods does not
> understand (by default?) how to respond to an "anonymous object" (no message
> name).
>
> Is there any way this could be implemented? I'll post an example soon
> (I currently use both Pharo 7 and 8)
>
> If I write the following:
>
> [:x | x + 1] value: 3
>
> and evaluate it, I get the expected result, which is 4.
>
> That's nice.
>
> What I would really like is to be able to just send 3 to BlockClosure and
> make it repond as above.
>
> Like this:
>
> [:x | x + 1] 3
>
> or like this:
>
> 3 [:x | x + 1]
>
> Would this be possible?
>
> -----------------------
>
> Also as a bonus, would it be possible to use this for "function
> composition", "Block composition" or similar?
>
> Example of composition:
>
> [ :f :g | [ :x | f value: (g value: x) ] ]
>
> I could use this construct like this for example:
>
> (([ :f :g | [ :x | f value: (g value: x) ] ])
> value: [:x | x + 1]
> value: [:x | x - 1])
> value: 5
>
> But… It's a bit wordy.
>
> What I would like to be able to do (essentialy remove "value:"):
>
> (([ :f :g | [ :x | f (g x) ] ])
> [:x | x + 1]
> [:x | x - 1])
> 5.
>
> Or in one line:
> (([ :f :g | [ :x | f (g x) ] ]) [:x | x + 1] [:x | x - 1]) 5.
>
> While this might seem obscure, I would really find it useful.
>
> Can it be done?
>
> Thanks in advance
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>

Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

Kasper Osterbye
In reply to this post by main
You can define a method "=>" in Object as:
=> aBlock
^ aBlock value: self
That would allow you to write expressions like this:
7 => [ :x | x+3 ] => [ :x| x*3 ], 

if you further define "=>" in Array as:
=> aBlock
^ aBlock valueWithArguments: self

you are able to write your example:
(([ :f :g | [ :x | f (g x) ] ]) [:x | x + 1] [:x | x - 1]) 5

as: 

5 => ({ [:x | x + 1].  [:x | x - 1]} => [ :f :g | [ :x | x => g =>f ] ]).

It reads from left to right where yours is the usual Arabic (right to left) favoured in functional style.

 
Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

main
That's great!

Thanks! Now I will write Pharo forever

I first thought of implementing the doesNotUnderstand, but I think this is a
better way!





--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Systems Architect,
Åkerströms
Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

philippeback
In reply to this post by Kasper Osterbye
It is like Object>>in: aBlock no?



On Wed, 23 Oct 2019, 10:27 Kasper Osterbye, <[hidden email]> wrote:
You can define a method "=>" in Object as:
=> aBlock
^ aBlock value: self
That would allow you to write expressions like this:
7 => [ :x | x+3 ] => [ :x| x*3 ], 

if you further define "=>" in Array as:
=> aBlock
^ aBlock valueWithArguments: self

you are able to write your example:
(([ :f :g | [ :x | f (g x) ] ]) [:x | x + 1] [:x | x - 1]) 5

as: 

5 => ({ [:x | x + 1].  [:x | x - 1]} => [ :f :g | [ :x | x => g =>f ] ]).

It reads from left to right where yours is the usual Arabic (right to left) favoured in functional style.

 
Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

Kasper Osterbye
On Wed, Oct 23, 2019 at 2:21 PM [hidden email] <[hidden email]> wrote:
It is like Object>>in: aBlock no?
Yes.

But because it is an operator, you can write "obj => block => block => block".
You can not write "obj in: block in: block in: block", because smalltalk will think it is a selector named "in:in:in:".

Best,

Kasper 
Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

philippeback


On Wed, 23 Oct 2019, 14:25 Kasper Osterbye, <[hidden email]> wrote:
On Wed, Oct 23, 2019 at 2:21 PM [hidden email] <[hidden email]> wrote:
It is like Object>>in: aBlock no?
Yes.

But because it is an operator, you can write "obj => block => block => block".
You can not write "obj in: block in: block in: block", because smalltalk will think it is a selector named "in:in:in:".

Indeed.

I would still use in: with parentheses instead of introducing a new (albeit cool) operator.

Phil


Best,

Kasper 
Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

main
Hi again!

Just putting it out there for anyone interested.

What I did was define the following in Object:

|> aBlock
        ^ [ :x | x => self => aBlock ]

and also:

=> msg
        ^ msg value: self


This enabled me to compose like this (I know I probably violate every rule
in the book, whatever ):

f :=  [ :x | x + 100 ].
g := [ :x | x +   20 ].
h := [ :x | x +     3 ].

0 => (f |> g |> h). 123

Also tried using ~:

0 => (f ~ g ~ h). 123

It's just a matter of taste I guess, but for me it warms my heart



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Systems Architect,
Åkerströms
Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

Steffen Märcker
Looks nice!

Just my two cents. To make function comopostion work with multiple
aruments, I implemented * as:

   BlockClosure class>>* first
     ^ComposedFunction first: first second: self

And use a dedicated class to make multiple arguments work:

   ComposedFunction>>value: arg
     ^second value: (first value: arg)

   ComposedFunction>>value: arg1 value: arg2
     ^second value: (first value: arg1 value arg2)

Then, we can write:

   [:x | x factorial ] * [:x :y | x + y]
     value: 1 value: 2


(I usually use the mathematical compostion operator, wich evalutes from
right to left.)

However, it is often convenient to interchange Symbols and Blocks, e.g.,
the above can be rewritten as

   #factorial * #+
     value: 1 value: 2

That requires to implement the * operator on symbols, too. And depending
on your Smalltalk implemenation, you may have to implement the evaluation
protocol on symbols.

Best, Steffen


Am .10.2019, 15:12 Uhr, schrieb main <[hidden email]>:

> Hi again!
>
> Just putting it out there for anyone interested.
>
> What I did was define the following in Object:
>
> |> aBlock
> ^ [ :x | x => self => aBlock ]
>
> and also:
>
> => msg
> ^ msg value: self
>
>
> This enabled me to compose like this (I know I probably violate every
> rule
> in the book, whatever ):
>
> f :=  [ :x | x + 100 ].
> g := [ :x | x +   20 ].
> h := [ :x | x +     3 ].
>
> 0 => (f |> g |> h). 123
>
> Also tried using ~:
>
> 0 => (f ~ g ~ h). 123
>
> It's just a matter of taste I guess, but for me it warms my heart
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

Sven Van Caekenberghe-2
In reply to this post by main
Hi Johan,

That is nice indeed. It is good to see that you have fun learning Pharo Smalltalk.

Can you do it ? Of course, you can do what you want, Pharo Smalltalk is a highly flexible environment.

Key to its simplicity are its ultra simple syntax which hits a magical optimum between simplicity and capability (full syntax on a postcard). With just messages and block, you can express almost anything (one limitation is that there are no macros).

Part of that is (for me at least), left to right evaluation/reading - trying to change that 'hurts'. Binary operators are useful and even necessary, but the problem with totally new uses is that readers won't understand them. Being a bit more verbose helps, in my opinion.

You might also be interested in the following:

 Lambda Calculus in Pharo
 Yes, the Y Combinator is useful in normal programs
 https://medium.com/concerning-pharo/lambda-calculus-in-pharo-a4a571869594

Regards,

Sven

> On 23 Oct 2019, at 15:12, main <[hidden email]> wrote:
>
> Hi again!
>
> Just putting it out there for anyone interested.
>
> What I did was define the following in Object:
>
> |> aBlock
> ^ [ :x | x => self => aBlock ]
>
> and also:
>
> => msg
> ^ msg value: self
>
>
> This enabled me to compose like this (I know I probably violate every rule
> in the book, whatever ):
>
> f :=  [ :x | x + 100 ].
> g := [ :x | x +   20 ].
> h := [ :x | x +     3 ].
>
> 0 => (f |> g |> h). 123
>
> Also tried using ~:
>
> 0 => (f ~ g ~ h). 123
>
> It's just a matter of taste I guess, but for me it warms my heart
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>


Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

Richard O'Keefe
In reply to this post by main
No kind of object does what you want.
You cannot do   3 3
or                      #x #y
As for [:x | x + 1] 3, what would be the *point* of doing this?
What is the block suppose to *do* with the 3?  Do you want to extend this
to [:x :y | x + y] 3 4 ?  If not, why not?  What about [3+4] "what to put here?"
As for composition, my own library has
 ( [:x | x + 1] before: [:y | y * 2] ) value: 10   => 22
 ( [:y | y * 2] after: [:x | x + 1] ) value: 10 => 22
with no magic syntax needed.

The |> operator in F# has been imitated in several other languages.
I've implemented it in my Smalltalk, and tested it, but never bothered to use
it.

Object
  methods for: 'combinators'
    |> unary
      ^(unary isMemberOf: NiladicSelector) "isKindOf: Symbol"
         ifTrue:  [unary send_to: self]    "self perform: unary"
         ifFalse: [unary value: self]

MonadicBlock
  methods for: 'invoking'
    collect
      ^[:collection | collection collect: self]

    do
      ^[:collection | collection      do: self]

    reject
      ^[:collection | collection  reject: self]

    select
      ^[:collection | collection  select: self]

NiladicSelector
  methods for: 'invoking'
    collect
      ^[:collection | collection collect: [:each | each perform: self]]

    do
      ^[:collection | collection      do: [:each | each perform: self]]

    reject
      ^[:collection | collection  reject: [:each | each perform: self]]

    select
      ^[:collection | collection  select: [:each | each perform: self]]

10 |> [:x | x+1] |> [:y | y*2]  ==> 22
#(1 2 3) |> [:x | x * 10] collect => #(10 20 30)

Reply | Threaded
Open this post in threaded view
|

Re: BlockClosure

Richard Sargent (again)
In reply to this post by philippeback


On October 23, 2019 5:46:50 AM PDT, "[hidden email]" <[hidden email]> wrote:

>On Wed, 23 Oct 2019, 14:25 Kasper Osterbye, <[hidden email]>
>wrote:
>
>> On Wed, Oct 23, 2019 at 2:21 PM [hidden email]
><[hidden email]>
>> wrote:
>>
>>> It is like Object>>in: aBlock no?
>>>
>> Yes.
>>
>> But because it is an operator, you can write "obj => block => block
>=>
>> block".
>> You can not write "obj in: block in: block in: block", because
>smalltalk
>> will think it is a selector named "in:in:in:".
>>
>
>Indeed.
>
>I would still use in: with parentheses instead of introducing a new
>(albeit
>cool) operator.

Especially when that particular selector has often been implemented as a shorthand for creating associations!


>
>Phil
>
>
>> Best,
>>
>> Kasper
>>