このチュートリアルに基づいて、以下のスニペットを作成しました。最後の 2 行 (feed_squid(FeederRP)
とfeed_red_panda(FeederSquid)
) は明らかに定義された制約に違反していますが、Dialyzer はそれらを問題ないと判断しています。これはまさに、静的分析を実行するツールでキャッチしたいタイプのエラーであるため、非常に残念です。
チュートリアルに説明があります:
関数が間違った種類のフィーダーで呼び出される前に、まず正しい種類で呼び出されます。R15B01 の時点で、Dialyzer はこのコードのエラーを検出しませんでした。観測された動作は、指定された関数への呼び出しが関数の本体内で成功するとすぐに、Dialyzer が同じコード単位内のそれ以降のエラーを無視することです。
この動作の根拠は何ですか? サクセスタイピングの背後にある哲学が「オオカミを決して泣かない」ことであることは理解していますが、現在のシナリオでは、Dialyzer は意図的に定義された関数仕様を明確に無視します (関数が以前に正しく呼び出されたことを確認した後)。コードがランタイム クラッシュを引き起こさないことを理解しています。どういうわけか、Dialyzer に常に関数の仕様を真剣に考えさせることはできますか? そうでない場合、それを行うことができるツールはありますか?
-module(zoo).
-export([main/0]).
-type red_panda() :: bamboo | birds | eggs | berries.
-type squid() :: sperm_whale.
-type food(A) :: fun(() -> A).
-spec feeder(red_panda) -> food(red_panda());
(squid) -> food(squid()).
feeder(red_panda) ->
fun() ->
element(random:uniform(4), {bamboo, birds, eggs, berries})
end;
feeder(squid) ->
fun() -> sperm_whale end.
-spec feed_red_panda(food(red_panda())) -> red_panda().
feed_red_panda(Generator) ->
Food = Generator(),
io:format("feeding ~p to the red panda~n", [Food]),
Food.
-spec feed_squid(food(squid())) -> squid().
feed_squid(Generator) ->
Food = Generator(),
io:format("throwing ~p in the squid's aquarium~n", [Food]),
Food.
main() ->
%% Random seeding
<<A:32, B:32, C:32>> = crypto:rand_bytes(12),
random:seed(A, B, C),
%% The zoo buys a feeder for both the red panda and squid
FeederRP = feeder(red_panda),
FeederSquid = feeder(squid),
%% Time to feed them!
feed_squid(FeederSquid),
feed_red_panda(FeederRP),
%% This should not be right!
feed_squid(FeederRP),
feed_red_panda(FeederSquid).