繁体   English   中英

在没有递归或编译器技巧的情况下,在仅消息语言中是否有一种方法来定义whileTrue消息?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM