开发者

Function objects in Smalltalk (or executing blocks with no `value:`)

Is it possible to send an anonymous message to an object? I want to compose three objects like this (think FP):

 " find inner product "
 reduce + (applyToAll * (transpose #(1 2 3) #(4 5 6)))

where reduce, applyToAll and transpose are objects and 开发者_运维百科+, * and the two arrays are arguments passed to anonymous messages sent to those objects. Is it possible to achieve the same using blocks? (but no explicit usage of value:).


Perhaps what you really want to do is define a DSL inside Smalltalk?

With HELVETIA we explore a lightweight approach to embed new languages into the host language. The approach reuses the existing toolchain of editor, parser, compiler and debugger by leveraging the abstract syntax tree (AST) of the host environment. Different languages cleanly blend into each other and into existing code.


aRealObject reduceMethod: +; 
            applyToAll: *; 
            transpose: #(#(1 2 3) #(4 5 6));
            evaluate

would work when aRealObject has defined the right methods. Where do you need a block?


You are looking for doesNotUnderstand:. If reduce is an object that does not implement + but you send it anyway, then instead its doesNotUnderstand: method will be invoked. Normally it just raises an error. But you can override the default, and access the selector + and the other argument and do whatever you like with them.

For simplicity, create a class Reduce. On its class side, define the method:

doesNotUnderstand: aMessage
    ^aMessage argument reduce: aMessage selector

Then you can use it like this:

Reduce + (#(1 2 3) * #(4 5 6))

which in a Squeak workspace answers 32, as expected.

It works because * is already implemented for Collections with suitable semantics.

Alternatively, add a class ApplyToAll with this class-side method:

doesNotUnderstand: aMessage
    ^aMessage argument collect: [:e | e reduce: aMessage selector]

and also add this method to SequenceableCollection:

transposed
    ^self first withIndexCollect: [:c :i | self collect: [:r | r at: i]]

Then you can write

Reduce + (ApplyToAll * #((1 2 3) #(4 5 6)) transposed)

which is pretty close to your original idea.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜