Yield Prolog adaptation for Smalltalk



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

Smalltalk中是否存在类似于收益和生成器的功能?

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

  • 发电机功能使用产量:

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)

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

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:的代码会立即执行。也就是说,在创建生成器时,将执行第一个yield:之前的所有代码。在第一次调用next,它执行直到第二个yield:的所有代码,但回答第一个结果的值。等等。这样生成器就可以检测何时停止执行(因为它是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实现是否与Squeak的实际Prolog一样有效。你应该看看:http://www.zogotounga.net/comp/squeak/prolog.htm

最新更新