为什么Dialyzer告诉我这个有趣的合同有重叠的域名?

时间:2012-08-30 12:54:53

标签: types erlang dialyzer

我感兴趣地阅读在线图书" learn you some erlang"并尝试一些练习来检查我的理解。

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

我的类型说明是:

  

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

     

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

     

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

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

  

-spec empty(typed_empty_fifo()) - >真;

  (typed_nonempty_fifo(_)) -> false.
     

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

     当is_list(A),is_list(B) - >时,

为空({fifo,A,B})假的。

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

有人可以告诉我哪里出错了吗?

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

这真的很奇怪,因为当我使用bif长度/ 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])

由于

2 个答案:

答案 0 :(得分:4)

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

对于第二个问题,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)。

答案 1 :(得分:0)

关于第二个问题,使用list的正确方法是:

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

请注意,[Head|Tail]要求Tail要求listint(而不是{{1}})。