Dialyzer可以通过Mnesia交易功能看到吗?

时间:2013-07-10 09:52:23

标签: erlang mnesia dialyzer

以下是一些错误的代码,我认为Dialyzer应该能够发现:

-module(myapp_thing).

-spec exists(pos_integer()) -> yes | no.
exists(Id) ->
    myapp_mnesia:thing_exists(Id).

-module(myapp_mnesia).

thing_exists(Id) ->
    Exists = fun() -> 
                     case mnesia:read({thing, Id}) of
                         [] -> false;
                         _ ->  true
                     end
             end,
    mnesia:activity(transaction, Exists).

myapp_thing:exists/1被指定为返回yes | no,但返回类型实际上是true | false(即boolean()),这是从{{1}返回的内容}。

然而,在myapp上运行Dialyzer会在没有警告的情况下通过它。

如果我将myapp_mnesia:thing_exists/1更改为只返回myapp_mnesia:thing_exists/1,我会收到相应的警告;同样,如果我添加正确的规范:

true

但看起来Dialyzer无法查看mnesia事务函数Exists内部,或者由于某些其他原因无法推断出thing_exists的返回类型。

那么,mnesia交易是Dialyzer的障碍,还是Dialyzer的返回类型推断存在更普遍的障碍?

1 个答案:

答案 0 :(得分:1)

mnesia_tm:execute_transaction中,在catch内调用提供的乐趣,这意味着就Dialyzer而言,返回类型会折叠为term()。因此,Dialyzer无法断定mnesia:activity/2的返回类型与提供的函数的返回类型相同,因此需要一个明确的类型规范。

此外,我认为Dialyzer通常不会根据作为参数提供的函数的返回值推断返回值类型。例如,使用此模块:

-module(foo).

-export([foo/1]).

foo(F) ->
    F(42).

typer显示以下内容:

$ typer /tmp/foo.erl

%% File: "/tmp/foo.erl"
%% --------------------
-spec foo(fun((_) -> any())) -> any().

虽然如果我添加显式类型规范-spec foo(fun((_) -> X)) -> X.,那么typer会接受它。

(我确信Dialyzer的开发人员会对此有更完整和深刻的回答。)