简体   繁体   English

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

[英]Is there a way in a message-only language to define a whileTrue message without recursion or compiler tricks?

Smalltalk has the whileTrue:-Message implemented through recursion (in VisualWorks) or through compiler-inlining (in Squeak/Pharo). Smalltalk有whileTrue:-Message通过递归(在VisualWorks中)或通过编译器内联(在Squeak / Pharo中)实现。 Is there a way to define such a method without using one of them? 有没有办法在不使用其中一种方法的情况下定义这样的方法? If not, is there a proof for that avaiable somewhere? 如果没有,是否有可以在某处获得的证明?

I propose the following solution: 我提出以下解决方案:

BlockContext>>myWhileTrue: aBlock 
    | start |
    start := thisContext pc.
    self value ifFalse: [ ^ self ].
    aBlock value.
    thisContext pc: start

Instead of using recursion and compiler tricks, the above code uses reflection on the execution stack. 上面的代码使用了对执行堆栈的反射,而不是使用递归和编译器技巧。 Before the loop starts the method stores the current program counter in a temporary variable and resets it at the end to jump back to the start of the method. 在循环开始之前,该方法将当前程序计数器存储在临时变量中,并在最后重置它以跳回到方法的开头。 In some Smalltalk implementations such an approach might be slow as some Smalltalk dialects reify the stack on demand only, but in Pharo/Squeak this trick is quite practicable. 在一些Smalltalk实现中,这种方法可能会很慢,因为一些Smalltalk方言仅仅根据需要重新启用堆栈,但在Pharo / Squeak中,这种技巧非常实用。

Note, the above code does not answer the result of the last block activation as the original implementation of #whileTrue: does. 注意,上面的代码没有回答最后一个块激活的结果,因为#whileTrue:的原始实现。 It should be easy enough to fix that though. 虽然应该很容易解决这个问题。

whileTrue: & whileFalse: always return nil. whileTrue:&whileFalse:总是返回nil。 eg if there is a normal recursive definition: 例如,如果存在正常的递归定义:

whileTrue: aBlock
    ^self value ifTrue: [self whileTrue: aBlock]

the ifTrue: will return nil if self value is false and so the value should always be nil. ifTrue:如果self值为false,则返回nil,因此值应始终为nil。 That's reflected in the compiler's optimization. 这反映在编译器的优化中。 The original blue book Smalltalk-80 V2 definition is 最初的蓝皮书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]

So just change your's to 所以只需改变你的

BlockContext>>myWhileTrue: aBlock 
    | start |
    start := thisContext pc.
    self value ifFalse: [ ^ nil ].
    aBlock value.
    thisContext pc: start

or?? 要么??

BlockContext>>myWhileTrue: aBlock 
    | start |
    start := thisContext pc.
    ^self value ifTrue:
        [aBlock value.
         thisContext pc: start]

But alas both of these crash the VM sometime after the second iteration because thisContext pc doesn't answer the pc on the next iteration, but instead whatever the top of stack is :) 但是这两个都在第二次迭代后的某个时候崩溃了,因为这个文本pc在下一次迭代时没有回答pc,而是堆栈的顶部是:)

However the following does work: 但是以下工作正常:

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]

You could also use an exception handler to make it go back to the beginning, but that might count as cheating if the exception handling code used a whileTrue: or other looping construct somewhere. 您还可以使用异常处理程序使其返回到开头,但如果异常处理代码在某处使用了whileTrue:或其他循环结构,那么这可能会被视为作弊。 So, basically, the question boils down to whether you can implement a loop without either goto or recursion, and I think the answer to that is no. 所以,基本上,问题归结为你是否可以实现一个没有goto或递归的循环,我认为答案是否定的。 So if recursion is forbidden, you're left trying to cobble together a goto out of techniques like setting the method pc or using an exception. 因此,如果禁止递归,那么你就会试图将诸如设置方法pc或使用异常之类的技术拼凑出来。

Just do: 做就是了:

BlockClousure>>whileTrue: aBlock BlockClousure >> whileTrue:aBlock

self value ifTrue: [ aBlock value. 自我值ifTrue:[aBlock值。 thisContext restart. thisContext重启。 "restart on pharo, reset on VW" ] “重启pharo,重置大众”]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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