我正在饶有兴趣地阅读在线书籍"学你一些二郎;尝试一些练习来检查我的理解能力。
在类型规范和Erlang一章中,我对fifo示例进行了一些修改,试图定义一个";typed_ fifo(T)";(一个fifo,其中所有元素必须是相同类型的T)
我的型号规格是:
-类型typed_empty_filfo()::{fifo,[],[]}。
-type typed_nonempty_filfo(A)::{fifo,nonempty_list(A),list(A)}|{fivo,[],nonempty _list(B)}。
-type typed_fifo(A)::typed_empty_filfo()| typed_nonempty_filFO(A)。
当我在以下功能规范中使用它时:
-规范为空(typed_empty_filfo())->真实;
(typed_nonempty_fifo(_)) -> false.
空({fifo,[],[]})->真实;
当is_list(A)、is_liist(B)->false。
Dialyzer告诉,由于域重叠,它将忽略规范。
有人能告诉我哪里出错了吗?
我还有一点,在尝试定义类型fifo之前,我有一个运行良好的版本,一个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])
感谢
您的类型和规范没有任何问题。问题是Dialyzer中用于表示类型的数据类型没有您提供的那么精确。具体来说,并集:{fifo, nonempty_list(A), list(A)} | {fifo, [], nonempty_list(A)}
被"粉碎"为{fifo, list(A), list(A)}
,因为元组具有相同的arity(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
)。
关于第二个问题,使用list
的正确方法是:
1> L = [1,2|[3]].
[1,2,3]
2> is_list(L).
true
3> length(L).
3
注意,[Head|Tail]
表示法要求Tail
为list
(而不是int
)。