簡體   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