3

我正在调试一个错误,发现它undefined已附加到一个列表中,这导致了后来的崩溃。

我预计使用++运算符附加列表以外的内容会导致崩溃。但这对于undefined. 这是一个例子:

1> [1,2,3] ++ undefined.
[1,2,3|undefined]

尽管它没有崩溃,但该列表不再具有全部功能:

1> L = [1,2,3] ++ undefined.
[1,2,3|undefined]
2> L ++ [4].
** exception error: bad argument
     in operator  ++/2
        called as [1,2,3|undefined] ++ [4]

为什么会这样?这与erlang中列表的底层实现有关吗?

4

2 回答 2

1

在 Erlang 中,所有术语都由一个紧凑的类似指针的值表示,称为Eterm. 列表操作函数似乎与类型无关。

从这个角度考虑:在 erlang VM 内部,所有 Eterm 都是平等的。头部和尾部列表操作操作被称为非常快。既然需要多次操作来评估 opaqueEterm类型以确定它是否是一个列表,那何必呢?

在这种情况下的预期结果是一个错误,而你确实得到了一个。最终。

对于信任程序员有一些话要说,当处理一个增加了几个周期并且经常使用的操作时,忽略一个错误的附加的潜在好处会叠加起来,唯一的惩罚是一个奇怪的错误。

于 2013-02-19T16:52:39.097 回答
1

原因是将它的++第二个参数附加到它的第一个参数的末尾,该参数必须是一个列表。它不对其第二个参数进行任何处理,它只是按原样附加它。所以:

1> [1,2,3] ++ undefined.
[1,2,3|undefined]
2> [1,2,3] ++ [undefined].
[1,2,3,undefined]

您可以这样做的原因以及:

3> [a|b].
[a|b]
4> [a|[b]].
[a,b]

是一个列表是一个序列列表单元格,一个单链表,而不是一个单一的数据结构。如果每个单元格的右侧(称为尾部)是另一个列表单元格,[]那么您将得到一个正确的列表。每个单元格的左侧称为头部,通常包含列表的元素。这就是我们在上面的 2 和 4 中的内容。大多数(如果不是全部)库函数都假定列表是正确的列表,如果不是,则会生成错误。请注意,您实际上必须将整个列表降级到最后,以查看它是否正确。

每个列表单元都写成,[Head|Tail]语法[a,b,c]只是[a|[b|[c|[]]]]. 请注意,每个列表单元的尾部都是一个列表,[]因此这是一个正确的列表。

对于列表单元的头部和尾部可以是什么类型没有限制。系统从不检查它只是做它。这就是我们在上面的 1 和 3 中所拥有的,其中最后一个列表单元格的尾部(仅 3 中的列表单元格)不是列表或[].

很抱歉在这里有点过度说教。

编辑:我看到我已经在这里描述了这个:函数式编程:什么是“不正确的列表”?

于 2013-02-20T13:43:04.253 回答