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



我正在饶有兴趣地阅读在线书籍"学你一些二郎;尝试一些练习来检查我的理解能力。

类型规范和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]表示法要求Taillist(而不是int)。

相关内容

  • 没有找到相关文章

最新更新