【发布时间】:2019-08-29 09:23:04
【问题描述】:
我试图了解透析器如何与多态/参数化类型一起工作。我理解这是乐观的,如果有任何通过代码的路径不会导致崩溃,它就会成功;鉴于这一事实,我不明白如何使用类型变量。
我有一个简单的递归二叉搜索树类型规范,旨在生成一个只有一种类型的值的 BST。我知道(例如)原子和整数在 Erlang 中是可比较的,但我不希望我的 BST 允许这些比较。我编写并导出了一个函数b/0,它用一个整数和一个原子构建了一个BST,并且透析器不兼容。
-module(bst).
-export([add/2, b/0, new/1]).
-type bst(T) :: {T, bst(T), bst(T)} | nil.
-spec new(T) -> bst(T).
-spec add(T, bst(T)) -> bst(T).
new(Root) -> {Root, nil, nil}.
add(Val, nil) -> {Val, nil, nil};
add(Val, {Root, Left, Right}) ->
case Val =< Root of
true -> {Root, add(Val, Left), Right};
false -> {Root, Left, add(Val, Right)}
end.
% Why no type error here? Adding atom to bst(integer()),
% but type spec allows only same type.
b() -> N = new(8), add(why_no_type_error, N).
运行透析器得到以下成功结果:
dialyzer-tests ❯ dialyzer bst.erl
Checking whether the PLT /home/.../.dialyzer_plt is up-to-date... yes
Proceeding with analysis... done in 0m0.12s
done (passed successfully)
我可以通过编辑我的add/2 规范使这个示例失败,如下所示:
-spec new(integer()) -> bst(integer());
(atom()) -> bst(atom()).
-spec add(integer(), bst(integer())) -> bst(integer());
(atom(), bst(atom())) -> bst(atom()).
这是惯用的,还是有更好的方法来做到这一点?我不一定要为我的树上的每个可能的操作详细说明每种可能的类型。
【问题讨论】:
-
你在哪里告诉拨号器 T 必须是整数或数字?没有这个限制,旅游代码是正确的
-
在我看来,这不是定义规范的正确方式。看我的帖子。