7

我正在阅读在线书籍“ learn you some erlang ”并尝试一些练习来检查我的理解。

我在类型规范和 Erlang章节中对 fifo 示例进行了一些修改,试图定义一个“typed_fifo(T)”(所有元素必须是相同类型 T 的 fifo)

我的类型规范是:

-typed_empty_fifo() :: {fifo, [], []}。

-typed_nonempty_fifo(A) :: {fifo, nonempty_list(A), list(A)} | {fifo, [],nonempty_list(A) }。

-typed_fifo(A) :: typed_empty_fifo() | typed_nonempty_fifo(A)。

当我在以下功能规范中使用它时:

-spec 空 (typed_empty_fifo()) -> true;

  (typed_nonempty_fifo(_)) -> false.

空({fifo,[],[]})-> 真;

当 is_list(A), is_list(B) -> false 时为空({fifo, A, B})。

Dialyzer 表示由于域重叠,它将忽略规范。

有人可以告诉我我在哪里犯了错误吗?

我还有一点,在尝试定义类型化的 fifo 之前,我有一个运行良好的版本,An Dialyzer 告诉我没有什么可以阻止使用不正确的列表。令人惊讶的是,我没有找到一种简单的方法(我可以在警卫中使用)来测试列表的正确/不正确字符。

真的很奇怪,因为当我使用 bif length/1 时,它会因为 badarg 的原因而失败!

23> L=[1,2|3]。==> [1,2|3]

24> is_list(L)。==> 真

25> 长度(L)。==> 异常错误:参数错误

 in function  length/1

    called as length([1,2|3])

谢谢

4

2 回答 2

4

您的类型和规格没有任何问题。问题是在 Dialyzer 中用于表示类型的数据类型没有保持您提供的精度。具体来说,并集:{fifo, nonempty_list(A), list(A)} | {fifo, [], nonempty_list(A)}被“压碎”成{fifo, list(A), list(A)},因为元组具有相同的元数 (3) 和第一个原子元素 ( fifo)。Dialyzer 通常会进行过度近似(您也可以在此处看到)以使类型分析更有效。您可以放心地忽略此警告。

对于第二个问题,is_list/1仅检查作为参数传递的术语的第一个构造函数是否是 cons 单元格。甚至is_list([1|2])回报true

如果要确保参数是正确的列表,可以在case如下表达式中使用自定义函数:

case is_proper_list(L) of
  true -> ...;
  false -> ...
end

is_proper_list([]) -> true;
is_proper_list([_|L]) -> is_proper_list(L);
is_proper_list(_) -> false.

然而,这不能放在守卫中。在警卫中,您可以使用您在下面的评论中建议的那个 ( length(L) >= 0)。

于 2012-08-30T19:24:02.343 回答
0

关于你的第二个问题,正确的工作方式list是:

1> L = [1,2|[3]].
[1,2,3]
2> is_list(L).
true
3> length(L).
3

请注意,该[Head|Tail]符号要求您Taillist(不是int)。

于 2012-08-30T13:49:23.990 回答