3
-module(test).
-export([f/0, g/0]).

-spec f() -> RESULT when
      RESULT :: 0..12 .

-spec g() -> RESULT when
      RESULT :: 0..13 .

f () -> 100 .

g () -> 100 .

运行透析器(和打字机)仅f捕获该功能。

dialyzer test.erl
Checking whether the PLT /Users/ben/.dialyzer_plt is up-to-date... yes
Proceeding with analysis...
test.erl:4: Invalid type specification for function test:f/0. The success typing is () -> 100
 done in 0m0.53s
done (warnings were emitted)

与打字机相同

typer test.erl
typer: Error in contract of function test:f/0
         The contract is: () -> RESULT when RESULT :: 0..12
         but the inferred signature is: () -> 100

这是“预期”的行为吗?

4

2 回答 2

3

是的,这是“预期的”行为。或者说“接受”。

免责声明:

  1. Dialyzer 从未承诺会捕获所有错误。
  2. 像上面这样的代码是相当人为的。

解释:

Dialyzer 的设计者决定使用这样的过度近似(除其他原因外)在分析递归函数时使工具的类型推断分析终止(达到固定点)(内部步骤看起来像这样:“factorial 的基本案例适用于0,所以它的递归情况也适用于 1,所以它也适用于 2,所以它也适用于 3,[...],所以它适用于 12,好吧,它也适用于 any char(),但它也适用于char_range + 1所以它适用于所有integers()“)。

这个(确实是任意的)限制变得至关重要是相当罕见的,而且,Dialyzer 从来没有承诺报告任何事情......

于 2017-04-10T09:08:30.187 回答
3

是的,这似乎是“预期的”。在这里查看源代码 它测试了

-define(SET_LIMIT, 13).

在测试中

t_from_range(X, Y) when is_integer(X), is_integer(Y) ->
  case ((Y - X) < ?SET_LIMIT) of 
    true -> t_integers(lists:seq(X, Y));
    false ->
      case X >= 0 of
    false -> 
      if Y < 0 -> ?integer_neg;
         true -> t_integer()
      end;
    true ->
      if Y =< ?MAX_BYTE, X >= 1 -> ?int_range(1, ?MAX_BYTE);
         Y =< ?MAX_BYTE -> t_byte();
         Y =< ?MAX_CHAR, X >= 1 -> ?int_range(1, ?MAX_CHAR);
         Y =< ?MAX_CHAR -> t_char();
         X >= 1         -> ?integer_pos;
         X >= 0         -> ?integer_non_neg
      end
      end
  end;

恕我直言,这似乎很危险,并且不提供任何真正的保证。绝对应该清楚地记录在案。在学习一些 Erlang网站上有传递参考。

整数范围。例如,如果您想表示一年中的几个月,可以定义范围 1..12。请注意,Dialyzer 保留将此范围扩大到更大范围的权利。

但是谷歌首页上没有任何官方使用关键字dialyzer integer ranges

编辑...看起来更近一点,如果您尝试,您会发现:

-module(test).
-export([h/0]).

-spec h() -> RESULT when
      RESULT :: 1..13 .

h () -> 100 .

透析器会捕捉到错误!(打字机不会)...

于 2017-04-09T15:44:19.203 回答