【问题标题】:Understanding GNU Smalltalk Closure了解 GNU Smalltalk 闭包
【发布时间】:2018-04-30 21:11:24
【问题描述】:

以下代码给出错误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)

【问题讨论】:

  • 请指定您正在使用的方言(我假设它是 GNU)以及更多错误消息,例如哪个类不理解该消息(如果有的话,可能发布一个堆栈跟踪)。
  • 看起来 SortedCollection 试图将 SmallIntegers 与您添加的对象(类 Tree?)进行比较并且失败。您的 pqueue 是否包含不同类型的元素?如果是这样,请确保它们可通过
  • 是的,这行得通。当我这样做时 [pqueue add: new_internal.]。它有效
  • 查看错误堆栈。您的代码正在尝试将 SmallInteger 与 codePoint 为 10Character 进行比较。这是用于生成换行符的换行符。可能这与表达式Tree new: nl count:... 中的变量nl 有关吗?
  • 是的,问题是 nl。感谢您的帮助。

标签: smalltalk gnu-smalltalk


【解决方案1】:

我们可以从这个问题中学到的一个知识是养成阅读堆栈跟踪以试图理解它的习惯。让我们关注最后几条消息:

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 &gt;&gt; #selector 对。我们可以从这些汇总信息中找出几个有趣的事实:

  1. 在第 1 行中,我们得到了实际错误。在这种情况下,我们得到了 MessageNotUnderstood 异常。消息的接收者是Character$&lt;10&gt;,即换行符。

  2. 第 2 行和第 3 行确认未理解的消息是 #generality

  3. 第 4、5 和 6 行显示了最终将 #generality 发送到错误对象(换行)的消息的进程。虽然对于没有经验的 Smalltalker 来说,第 4 行和第 5 行可能看起来晦涩难懂,但第 6 行有关键信息:一些SmallInteger 收到了&lt;= 消息。此消息将失败,因为该参数不合适。根据我们已经得到的信息,我们知道参数是换行符。

  4. 第 7 行显示 SmallInteger &gt;&gt; #&lt;= 来自 Leaf 中实现相同选择器 #&lt;= 的方式。它告诉我们Leaf#&lt;= 委托给它已知的一些Integer

  5. 第 8 行说明了我们处理比较选择器 #&lt;= 的原因。原因是我们正在对一些集合进行排序。

因此,我们正在尝试对一组 Leaf 对象进行排序,这些对象依赖于一些整数进行比较,并且不知何故,其中一个“整数”不是 Number 而是 Character 换行符。

如果我们带着这些信息看一下 Smalltalk 代码,我们会看到:

  • SortedCollectionpqueueLeaf 对象是要添加到其中的项目。

  • SortedCollection不变 属性是它的元素始终按给定标准排序。因此,每次我们向它add: 一个元素时,该元素都会被插入到正确的位置。因此,比较消息#&lt;=

  • 现在让我们在代码中查找#add:。除了上面一个,下面还有一个:

      new_internal := Tree new: nl count: newcount left: first right: second.
      pqueue add: new_internal.
    

    这个很有趣,因为它是错误发生的地方。但是请注意,我们在这里添加的不是Leaf,而是Tree。但是等等,TreeLeaf 可能属于同一个层次结构。事实上,TreeLeaf 都表示无环图中的节点。此外,该代码在以下内容中证实了这一想法:

      Leaf new: key count: value.
      ...
      Tree new: nl count: newcount left: first right: second.
    

看到了吗? LeafTree 都有一些 keynew: 的参数)和一些 count。此外,Treesleftright 分支,其中Leafs 没有(当然!)

因此,原则上,可以将Tree 的实例添加到我们的pqueue 集合中。这不可能是导致错误的原因。

现在,如果我们仔细观察Tree 的创建方式,我们可以看到一个可疑的参数nl。这很有趣,因为有两个原因:(i)变量nl 没有在我们给出的代码部分中定义,(ii)变量nlkey,将被@987654372 使用@ 回复#&lt;= 消息。因此,nl 必须是换行符$&lt;10&gt;。这很有意义,因为 nlnewline 的缩写,而在 Linux 世界中,换行符是换行符。

结论:问题似乎是由错误的参数nl用于Tree的键引起的。

【讨论】:

    猜你喜欢
    • 2018-08-19
    • 1970-01-01
    • 2014-08-25
    • 2021-06-25
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多