【发布时间】:2022-03-03 08:14:50
【问题描述】:
背景
我正在尝试使用透析器进行多态输入。作为一个例子,我使用了著名的Option 类型(又名,Maybe Monad),它现在在许多其他语言中很流行。
defmodule Test do
@type option(t) :: some(t) | nothing
@type some(t) :: [{:some, t}]
@type nothing :: []
@spec validate_name(String.t()) :: option(String.t())
def validate_name(name) do
if String.length(name) > 0 do
[{:some, name}]
else
nil
end
end
end
如您所见,函数 validate_name 应该返回(根据规范定义)[{:some, String.t}] | []。
这里的问题是,实际上,该函数返回[{:some, String.t}] | nil。 nil 与空列表[] 不同。
问题
考虑到这个问题,我希望透析器会抱怨。但是它很乐意接受这个错误的规范:
$ mix dialyzer
Compiling 1 file (.ex)
Finding suitable PLTs
Checking PLT...
[:compiler, :currying, :elixir, :gradient, :gradualizer, :kernel, :logger, :stdlib, :syntax_tools]
PLT is up to date!
No :ignore_warnings opt specified in mix.exs and default does not exist.
Starting Dialyzer
[
check_plt: false,
init_plt: '/home/user/Workplace/fl4m3/grokking_fp/_build/dev/dialyxir_erlang-24.2.1_elixir-1.13.2_deps-dev.plt',
files: ['/home/user/Workplace/fl4m3/grokking_fp/_build/dev/lib/grokking_fp/ebin/Elixir.Book.beam',
'/home/user/Workplace/fl4m3/grokking_fp/_build/dev/lib/grokking_fp/ebin/Elixir.DealingWithListsOfLists.beam',
'/home/user/Workplace/fl4m3/grokking_fp/_build/dev/lib/grokking_fp/ebin/Elixir.Event.beam',
'/home/user/Workplace/fl4m3/grokking_fp/_build/dev/lib/grokking_fp/ebin/Elixir.FlatMapsVSForComprehensions.beam',
'/home/user/Workplace/fl4m3/grokking_fp/_build/dev/lib/grokking_fp/ebin/Elixir.ImmutableValues.beam',
...],
warnings: [:unknown]
]
Total errors: 0, Skipped: 0, Unnecessary Skips: 0
done in 0m1.09s
done (passed successfully)
此外,无论我在else 分支中放什么,结果始终是“快乐的透析器”。
问题
此时,我能想到的唯一合乎逻辑的解决方案是透析器仅关注幸福路径。意思是,它将忽略我的else 分支。
如果 dialzyer 只关心快乐路径,那么这可以解释问题(毕竟它被称为成功输入),但这也意味着它会完全错过我的代码中的一堆错误。
- 我对透析器的假设是否正确?
- 有没有办法让它更精确地发现错误,或者这是透析器使用的算法的限制? (因此无法修复)
【问题讨论】: