产量Prolog适应Smalltalk

时间:2017-04-11 08:00:00

标签: prolog smalltalk yield

如何使http://yieldprolog.sourceforge.net中描述的方法适应Pharo Smalltalk?

类似于Smalltalk中存在的产量和发电机功能吗?

首先,我应该如何使用消息传递重写Tutorial1中的代码:

  • 使用yield的生成器函数:

class UnifyingVariable: def __init__(self): self._isBound = False def unify(self, arg): if not self._isBound: self._value = arg self._isBound = True yield False # Remove the binding. self._isBound = False elif self._value == arg: yield False

def personWithUnify(Person): for l1 in Person.unify("Chelsea"): yield False for l1 in Person.unify("Hillary"): yield False for l1 in Person.unify("Bill"): yield False

def main(): print("Names using UnifyingVariable:") Person = UnifyingVariable() for l1 in personWithUnify(Person): print(Person._value)

是否可以使用单线程实现,避免多线程会导致很多复杂性?

1 个答案:

答案 0 :(得分:4)

Squeak Smalltalk有一个Generator类,有一个yield:方法(如果Pharo没有删除它,那么它应该仍然存在)。

在Smalltalk中,yield不是其他语言中的关键字,而是在Smalltalk本身中实现。它使用带有协同例程的单个线程(操纵执行上下文)。

这是YieldProlog的第一个例子:

personWithReturnValue := Generator on: [ :g |
    g yield: 'Chelsea'.
    g yield: 'Hillary'.
    g yield: 'Bill' ].

Transcript cr; show: 'Names using a return value:'.
personWithReturnValue do: [ :p |
    Transcript cr; show: p ].

只要生成器无副作用,它就可以像其他语言一样使用。

然而,YieldProlog在统一其变量时依赖于副作用。区别在于,在Squeak中,直到下一个yield:的代码立即执行。也就是说,在创建Generator时,直到第一个yield:的所有代码都会被执行。在第一个next调用中,它会执行第二个yield:之前的所有代码,但会回答第一个yield的值。等等。这样,Generator可以检测何时停止执行(因为它是Stream的子类,需要支持其atEnd接口)。

这意味着你必须在产量之后加上副作用。例如。对于第二个YieldProlog示例,它可以工作:

Object subclass: #SimpleVariable
    instanceVariableNames: '_value'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'YieldProlog'.

SimpleVariable createInstVarAccessors.

personWithSimpleVariable := [ :person |
    Generator on: [ :g |
        g yield: false.
        person _value: 'Chelsea'.

        g yield: false. 
        person _value: 'Hillary'.

        g yield: false.
        person _value: 'Bill' ] ].

Transcript cr; show: 'Names using a SimpleVariable:'.
p := SimpleVariable new.
(personWithSimpleVariable value: p) do: [ :l1 |
    Transcript cr; show: p _value ].

但总的来说这使得很难正确实现YieldProlog。现在,由于Generator是在Smalltalk中实现的,因此解决此问题也相对容易。请参阅http://forum.world.st/Generators-td4941886.html

上发布的变更集

通过该更改,UnifyingVariable示例有效:

Object subclass: #UnifyingVariable
    instanceVariableNames: '_value _isBound'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'YieldProlog'.

UnifyingVariable createInstVarAccessors.

UnifyingVariable compile: 'unify: arg
    ^Generator on: [ :g |
        _isBound = true
            ifFalse: [ 
                _value := arg.
                _isBound := true.
                g yield: false.
                "Remove the binding".
                _isBound := false ]
            ifTrue: [
                _value = arg
                    ifTrue: [ g yield: false ] ] ]'.

personWithUnify := [ :person |
    Generator on: [:g |
        (person unify: 'Chelsea') do: [ :l1 |
            g yield: false ].
        (person unify: 'Hillary') do: [ :l1 |
            g yield: false ].
        (person unify: 'Bill') do: [ :l1 |
            g yield: false ] ] ].

Transcript cr; show: 'Names using a UnifyingVariable:'.
person := UnifyingVariable new.
(personWithUnify value: person) do: [ :l1 |
    Transcript cr; show: person _value ].

Transcript cr; show: 'Use unify to check a person:'.
person := UnifyingVariable new.
(person unify: 'Hillary') do: [ :l1 |
    (personWithUnify value: person) do: [ :l2 |
        Transcript cr; show: 'Hillary is a person.' ] ].
(person unify: 'Buddy') do: [ :l1 |
    (personWithUnify value: person) do: [ :l2 |
        "This won't print."
        Transcript cr; show: 'Buddy is a person.' ] ].

所有这些都说,我怀疑这个YieldProlog实现和实际的Prolog for Squeak一样有效。你应该看一下:http://www.zogotounga.net/comp/squeak/prolog.htm