了解 GNU Smalltalk 闭包
Understanding GNU Smalltalk Closure
下面的一段代码给出了错误 error: did not understand '#generality'
pqueue := SortedCollection new.
freqtable keysAndValuesDo: [:key :value |
(value notNil and: [value > 0]) ifTrue: [
|newvalue|
newvalue := Leaf new: key count: value.
pqueue add: newvalue.
]
].
[pqueue size > 1] whileTrue:[
|first second new_internal newcount|
first := pqueue removeFirst.
second := pqueue removeFirst.
first_count := first count.
second_count := second count.
newcount := first_count + second_count.
new_internal := Tree new: nl count: newcount left: first right: second.
pqueue add: new_internal.
].
不一致在行 pqueue add: new_internal
中。当我删除这一行时,程序会编译。我认为问题与迭代块 [pqueue size > 1] whileTrue:
和 pqueue add: new_internal.
有关
注:这是基于哈夫曼码构建解码树的算法。
错误消息扩展
Object: $<10> error: did not understand #generality
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
SmallInteger>><= (SmallInt.st:215)
Leaf>><= (hzip.st:30)
optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
SortedCollection>>insertionIndexFor:upTo: (SortCollect.st:702)
[] in SortedCollection>>merge (SortCollect.st:531)
SortedCollection(SequenceableCollection)>>reverseDo: (SeqCollect.st:958)
SortedCollection>>merge (SortCollect.st:528)
SortedCollection>>beConsistent (SortCollect.st:204)
SortedCollection(OrderedCollection)>>removeFirst (OrderColl.st:295)
optimized [] in UndefinedObject>>executeStatements (hzip.st:156)
BlockClosure>>whileTrue: (BlkClosure.st:328)
UndefinedObject>>executeStatements (hzip.st:154)
Object: $<10> error: did not understand #generality
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
SmallInteger>><= (SmallInt.st:215)
Leaf>><= (hzip.st:30)
optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
SortedCollection>>insertionIndexFor:upTo: (SortCollect.st:702)
[] in SortedCollection>>merge (SortCollect.st:531)
SortedCollection(SequenceableCollection)>>reverseDo: (SeqCollect.st:958)
SortedCollection>>merge (SortCollect.st:528)
SortedCollection>>beConsistent (SortCollect.st:204)
SortedCollection(OrderedCollection)>>do: (OrderColl.st:64)
UndefinedObject>>executeStatements (hzip.st:164)
我们可以从这个问题中学到的一个知识是养成阅读堆栈跟踪以试图理解它的习惯。让我们关注最后几条消息:
1. Object: $<10> error: did not understand #generality
2. MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
3. Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
4. SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
5. SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
6. SmallInteger>><= (SmallInt.st:215)
7. Leaf>><= (hzip.st:30)
8. optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
每一行代表一个方法的激活。每行代表一条消息,消息的顺序向上(就像在任何 Stack
中发生的那样)。可以在调试器中看到每个激活的完整细节。然而,在这里,我们只看到 class >> #selector
对。我们可以从这些汇总信息中发现几个有趣的事实:
在第 1 行中,我们得到了实际错误。在这种情况下,我们得到了一个 MessageNotUnderstood
异常。消息的接收者是 Character
$<10>
,即换行符。
第 2 行和第 3 行确认未理解的消息是 #generality
。
第 4、5 和 6 行显示了最终将 #generality
发送到错误对象(换行)的消息的进程。虽然第 4 行和第 5 行对于没有经验的 Smalltalker 来说可能看起来晦涩难懂,但第 6 行具有关键信息:一些 SmallInteger
收到了 <=
消息。此消息将失败,因为参数不合适。根据我们已经得到的信息,我们知道参数是换行符。
第 7 行显示 SmallInteger >> #<=
来自相同选择器 #<=
在 Leaf
中的实现方式。它告诉我们 Leaf
将 #<=
委托给它已知的某些 Integer
。
第 8 行说明了我们为什么要处理比较选择器 #<=
。原因是我们正在整理一些集合。
因此,我们正在尝试对 Leaf
对象的集合进行排序,这些对象依赖于一些整数进行比较,但其中一个 "integers" 不是 Number
,而是Character
换行。
如果我们在考虑这些信息的情况下查看 Smalltalk 代码,我们会看到:
SortedCollection
是 pqueue
,Leaf
对象是添加到其中的项目。
SortedCollection
的不变属性是它的元素总是按照给定的标准排序。因此,每次我们向它 add:
一个元素时,该元素都会被插入到正确的位置。因此比较消息 #<=
.
现在让我们在代码中查找#add:
。除了上面那个,下面还有一个:
new_internal := Tree new: nl count: newcount left: first right: second.
pqueue add: new_internal.
这个很有趣,因为这是错误发生的地方。但是请注意,我们在这里添加的不是 Leaf
,而是 Tree
。但是等等,可能 Tree
和 Leaf
属于同一层次结构。实际上,Tree
和Leaf
都代表无环图中的个节点。此外,代码在读取时证实了这个想法:
Leaf new: key count: value.
...
Tree new: nl count: newcount left: first right: second.
看到了吗? Leaf
和Tree
都有一些key
(new:
的参数)和一些count
。此外,Trees
有 left
和 right
分支,Leaf
没有(当然!)
因此,原则上,可以将 Tree
的实例添加到我们的 pqueue
集合中。这不可能是导致错误的原因。
现在,如果我们仔细观察 Tree
的创建方式,我们可以看到一个可疑的参数 nl
。这很有趣,原因有二:(i) 变量 nl
没有在我们给出的代码部分定义,以及 (ii) 变量 nl
是 key
被 Tree
用于响应 #<=
消息。因此,nl
必须是换行符 $<10>
。这很有意义,因为 nl
是 newline
的缩写,而在 Linux 世界中,换行符是换行符。
结论:问题似乎是由于 Tree
的密钥使用了错误的参数 nl
。
下面的一段代码给出了错误 error: did not understand '#generality'
pqueue := SortedCollection new.
freqtable keysAndValuesDo: [:key :value |
(value notNil and: [value > 0]) ifTrue: [
|newvalue|
newvalue := Leaf new: key count: value.
pqueue add: newvalue.
]
].
[pqueue size > 1] whileTrue:[
|first second new_internal newcount|
first := pqueue removeFirst.
second := pqueue removeFirst.
first_count := first count.
second_count := second count.
newcount := first_count + second_count.
new_internal := Tree new: nl count: newcount left: first right: second.
pqueue add: new_internal.
].
不一致在行 pqueue add: new_internal
中。当我删除这一行时,程序会编译。我认为问题与迭代块 [pqueue size > 1] whileTrue:
和 pqueue add: new_internal.
注:这是基于哈夫曼码构建解码树的算法。
错误消息扩展
Object: $<10> error: did not understand #generality
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
SmallInteger>><= (SmallInt.st:215)
Leaf>><= (hzip.st:30)
optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
SortedCollection>>insertionIndexFor:upTo: (SortCollect.st:702)
[] in SortedCollection>>merge (SortCollect.st:531)
SortedCollection(SequenceableCollection)>>reverseDo: (SeqCollect.st:958)
SortedCollection>>merge (SortCollect.st:528)
SortedCollection>>beConsistent (SortCollect.st:204)
SortedCollection(OrderedCollection)>>removeFirst (OrderColl.st:295)
optimized [] in UndefinedObject>>executeStatements (hzip.st:156)
BlockClosure>>whileTrue: (BlkClosure.st:328)
UndefinedObject>>executeStatements (hzip.st:154)
Object: $<10> error: did not understand #generality
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
SmallInteger>><= (SmallInt.st:215)
Leaf>><= (hzip.st:30)
optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
SortedCollection>>insertionIndexFor:upTo: (SortCollect.st:702)
[] in SortedCollection>>merge (SortCollect.st:531)
SortedCollection(SequenceableCollection)>>reverseDo: (SeqCollect.st:958)
SortedCollection>>merge (SortCollect.st:528)
SortedCollection>>beConsistent (SortCollect.st:204)
SortedCollection(OrderedCollection)>>do: (OrderColl.st:64)
UndefinedObject>>executeStatements (hzip.st:164)
我们可以从这个问题中学到的一个知识是养成阅读堆栈跟踪以试图理解它的习惯。让我们关注最后几条消息:
1. Object: $<10> error: did not understand #generality
2. MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
3. Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
4. SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
5. SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
6. SmallInteger>><= (SmallInt.st:215)
7. Leaf>><= (hzip.st:30)
8. optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
每一行代表一个方法的激活。每行代表一条消息,消息的顺序向上(就像在任何 Stack
中发生的那样)。可以在调试器中看到每个激活的完整细节。然而,在这里,我们只看到 class >> #selector
对。我们可以从这些汇总信息中发现几个有趣的事实:
在第 1 行中,我们得到了实际错误。在这种情况下,我们得到了一个
MessageNotUnderstood
异常。消息的接收者是Character
$<10>
,即换行符。第 2 行和第 3 行确认未理解的消息是
#generality
。第 4、5 和 6 行显示了最终将
#generality
发送到错误对象(换行)的消息的进程。虽然第 4 行和第 5 行对于没有经验的 Smalltalker 来说可能看起来晦涩难懂,但第 6 行具有关键信息:一些SmallInteger
收到了<=
消息。此消息将失败,因为参数不合适。根据我们已经得到的信息,我们知道参数是换行符。第 7 行显示
SmallInteger >> #<=
来自相同选择器#<=
在Leaf
中的实现方式。它告诉我们Leaf
将#<=
委托给它已知的某些Integer
。第 8 行说明了我们为什么要处理比较选择器
#<=
。原因是我们正在整理一些集合。
因此,我们正在尝试对 Leaf
对象的集合进行排序,这些对象依赖于一些整数进行比较,但其中一个 "integers" 不是 Number
,而是Character
换行。
如果我们在考虑这些信息的情况下查看 Smalltalk 代码,我们会看到:
SortedCollection
是pqueue
,Leaf
对象是添加到其中的项目。SortedCollection
的不变属性是它的元素总是按照给定的标准排序。因此,每次我们向它add:
一个元素时,该元素都会被插入到正确的位置。因此比较消息#<=
.现在让我们在代码中查找
#add:
。除了上面那个,下面还有一个:new_internal := Tree new: nl count: newcount left: first right: second. pqueue add: new_internal.
这个很有趣,因为这是错误发生的地方。但是请注意,我们在这里添加的不是
Leaf
,而是Tree
。但是等等,可能Tree
和Leaf
属于同一层次结构。实际上,Tree
和Leaf
都代表无环图中的个节点。此外,代码在读取时证实了这个想法:Leaf new: key count: value. ... Tree new: nl count: newcount left: first right: second.
看到了吗? Leaf
和Tree
都有一些key
(new:
的参数)和一些count
。此外,Trees
有 left
和 right
分支,Leaf
没有(当然!)
因此,原则上,可以将 Tree
的实例添加到我们的 pqueue
集合中。这不可能是导致错误的原因。
现在,如果我们仔细观察 Tree
的创建方式,我们可以看到一个可疑的参数 nl
。这很有趣,原因有二:(i) 变量 nl
没有在我们给出的代码部分定义,以及 (ii) 变量 nl
是 key
被 Tree
用于响应 #<=
消息。因此,nl
必须是换行符 $<10>
。这很有意义,因为 nl
是 newline
的缩写,而在 Linux 世界中,换行符是换行符。
结论:问题似乎是由于 Tree
的密钥使用了错误的参数 nl
。