我感兴趣地阅读在线图书" 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])
由于
答案 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
要求list
为int
(而不是{{1}})。