[英]How is Smalltalk's whileTrue message implemented behind the scenes?
[英]Is there a way in a message-only language to define a whileTrue message without recursion or compiler tricks?
Smalltalk有whileTrue:-Message通过递归(在VisualWorks中)或通过编译器内联(在Squeak / Pharo中)实现。 有没有办法在不使用其中一种方法的情况下定义这样的方法? 如果没有,是否有可以在某处获得的证明?
我提出以下解决方案:
BlockContext>>myWhileTrue: aBlock
| start |
start := thisContext pc.
self value ifFalse: [ ^ self ].
aBlock value.
thisContext pc: start
上面的代码使用了对执行堆栈的反射,而不是使用递归和编译器技巧。 在循环开始之前,该方法将当前程序计数器存储在临时变量中,并在最后重置它以跳回到方法的开头。 在一些Smalltalk实现中,这种方法可能会很慢,因为一些Smalltalk方言仅仅根据需要重新启用堆栈,但在Pharo / Squeak中,这种技巧非常实用。
注意,上面的代码没有回答最后一个块激活的结果,因为#whileTrue:的原始实现。 虽然应该很容易解决这个问题。
whileTrue:&whileFalse:总是返回nil。 例如,如果存在正常的递归定义:
whileTrue: aBlock
^self value ifTrue: [self whileTrue: aBlock]
ifTrue:如果self值为false,则返回nil,因此值应始终为nil。 这反映在编译器的优化中。 最初的蓝皮书Smalltalk-80 V2定义是
whileTrue: aBlock
"Evaluate the argument, aBlock, as long as the value
of the receiver is true. Ordinarily compiled in-line.
But could also be done in Smalltalk as follows"
^self value
ifTrue:
[aBlock value.
self whileTrue: aBlock]
所以只需改变你的
BlockContext>>myWhileTrue: aBlock
| start |
start := thisContext pc.
self value ifFalse: [ ^ nil ].
aBlock value.
thisContext pc: start
要么??
BlockContext>>myWhileTrue: aBlock
| start |
start := thisContext pc.
^self value ifTrue:
[aBlock value.
thisContext pc: start]
但是这两个都在第二次迭代后的某个时候崩溃了,因为这个文本pc在下一次迭代时没有回答pc,而是堆栈的顶部是:)
但是以下工作正常:
ContextPart methods for controlling
label
^{ pc. stackp }
goto: aLabel
"N.B. we *must* answer label so that the
top of stack is aLabel as it is when we send label"
pc := aLabel at: 1.
self stackp: (aLabel at: 2).
^aLabel
BlockContext>>myWhileTrue: aBlock
| label |
label := thisContext label.
self value ifFalse: [^nil].
aBlock value.
thisContext goto: label
BlockClosure>>myWhileTrue: aBlock
| label |
label := thisContext label.
^self value ifTrue:
[aBlock value.
thisContext goto: label]
您还可以使用异常处理程序使其返回到开头,但如果异常处理代码在某处使用了whileTrue:或其他循环结构,那么这可能会被视为作弊。 所以,基本上,问题归结为你是否可以实现一个没有goto或递归的循环,我认为答案是否定的。 因此,如果禁止递归,那么你就会试图将诸如设置方法pc或使用异常之类的技术拼凑出来。
做就是了:
BlockClousure >> whileTrue:aBlock
自我值ifTrue:[aBlock值。 thisContext重启。 “重启pharo,重置大众”]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.