Smalltalk 修改闭包的内容

Smalltalk 修改闭包的内容,smalltalk,pharo,Smalltalk,Pharo,有没有比以下更好的方法: |aBlock| aBlock := [3+2]. aBlock := Object readFrom: (a printString copyReplaceAll: '3' with: '2'). ? 编辑这段代码只是一个示例,下面的内容如何: [:something | something checkSomethingElse ifNil: [whatever] ifNotNil: [something get

有没有比以下更好的方法:

|aBlock|
aBlock := [3+2].
aBlock := Object readFrom: (a printString copyReplaceAll: '3' with: '2').
?

编辑这段代码只是一个示例,下面的内容如何:

[:something | 
    something checkSomethingElse ifNil: 
        [whatever] 
    ifNotNil:
        [something getSomethingDone]]
现在我想检查其他东西而不是检查其他东西

或:

现在我想添加第三个参数,并:

[:oneParameter :anotherParameter :yetAnotherParameter | 
    oneParameter doSomethingWith: anotherParameter and: yetAnotherParameter]

当然,您可以使用反射来操作块,但最干净的解决方案是通过用另一个块包装来动态绑定块中的值:

factory := [ :a :b | [ a + b ] ].
工厂
生成块,其中a和b绑定到不同的值:

aBlock := factory value: 3 value: 2.

评估
aBlock
答案
5

当然,您可以使用反射来操作块,但最干净的解决方案是通过用另一个块包装来动态绑定块中的值:

factory := [ :a :b | [ a + b ] ].
工厂
生成块,其中a和b绑定到不同的值:

aBlock := factory value: 3 value: 2.

评估
aBlock
答案
5

将块序列化为字符串并执行字符串操作,虽然很方便,但如果您对块的内容没有非常清楚的概念,则也是非常危险的

听起来您希望能够操作块的AST—给定一个块,解析它,更改结构(在本例中替换文本),然后编译更改后的结构。为此,您可以这样做:

| aBlock ast |
aBlock := [3+2].
ast := aBlock decompile.
ast statements first receiver: (DecompilerConstructor new codeAnyLiteral: 4).
aBlock := (Compiler evaluate: ast printString) first.
aBlock value. "==> 6"
请注意,我们实际上并没有改变aBlock,而是创建了aBlock的变异副本

该原则适用于更一般的情况:反编译块,执行操作(例如,在消息发送链的中途更改选择器),编译新的解析树。(我不知道如何直接编译树,而不是评估打印出来的树,但我相信有一种方法。)


(注意:我已经用Squeak写了上面的内容。我不知道Pharo的新编译器Opal的使用情况,所以也许你可以在Pharo中做一些稍微不同的事情。)

将块序列化为字符串并进行字符串操作,虽然很方便,但如果你对块的内容没有非常清楚的概念,这也是非常危险的

听起来您希望能够操作块的AST—给定一个块,解析它,更改结构(在本例中替换文本),然后编译更改后的结构。为此,您可以这样做:

| aBlock ast |
aBlock := [3+2].
ast := aBlock decompile.
ast statements first receiver: (DecompilerConstructor new codeAnyLiteral: 4).
aBlock := (Compiler evaluate: ast printString) first.
aBlock value. "==> 6"
请注意,我们实际上并没有改变aBlock,而是创建了aBlock的变异副本

该原则适用于更一般的情况:反编译块,执行操作(例如,在消息发送链的中途更改选择器),编译新的解析树。(我不知道如何直接编译树,而不是评估打印出来的树,但我相信有一种方法。)


(注意:我已经在Squeak中写了上面的内容。我不知道Pharo的新编译器Opal的运行状态,所以也许您可以在Pharo中做一些稍微不同的事情。)

这根本不会修改块。。。我的意思是像在MyClass compile:aMethod中那样进行修改,但用于闭包。当然,它不会修改块,但会修改现有块的行为。如果有人持有对区块的引用,它将在估值之间观察到不同的行为,这对他来说几乎与区块发生变化时一样。请注意,我很少在代码中选择这样的行为,我更喜欢Lukas建议的工厂块。改变其行为的块:)这根本不会修改块。。。我的意思是像在MyClass compile:aMethod中那样进行修改,但用于闭包。当然,它不会修改块,但会修改现有块的行为。如果有人持有对区块的引用,它将在估值之间观察到不同的行为,这对他来说几乎与区块发生变化时一样。请注意,我很少在代码中选择这样的行为,我更喜欢Lukas建议的工厂块。改变他们行为的积木:我应该解释我自己。前面的代码只是一个示例,我的意思是如何使用反射操作块:)我应该解释一下。前面的代码只是一个示例,我的意思是如何使用反射来操作块:),因为在Smalltalk中,我可以:PYou可以使用#perform:和co.来更改测试方法。因此:
[:something:selectorCheck |(something-perform:selectorCheck)ifNil:[…]
。对于可变大小参数,请使用
#perform:WithArgs:
方法。您还可以使用block
[:what | what value ifNil:[…]
。这里的想法是,在Smalltalk中有很多方法可以实现目标。但是更改源代码并进行评估应该保留到极端情况。(如果您正在编写某种解释器)因为,在Smalltalk中,I can:PYou可以使用#perform:and co.来更改测试方法。因此:
[:something:selectorCheck |(something-perform:selectorCheck)ifNil:[…]
。对于可变大小参数,请使用
#perform:WithArgs:
方法。您还可以使用block
[:what | what value ifNil:[…]
。这里的想法是,在Smalltalk中有很多方法可以实现目标。但是更改源代码并进行评估应该保留到极端情况。(如果您正在编写某种翻译。)