这不是错误:
defmodule Blog.UserResolver do
@type one_user :: ( {:error, String.t} )
@spec find(%{id: String.t}, any()) :: one_user
def find(%{id: id}, _info) do
age = :rand.uniform(99)
if (age < 100) do
# This doesn't trigger a type error, even though it's wrong
{:ok, %{email: "dw@1g.io", name: "Deedub"}}
else
{:error, "Age isn't in the right range"}
end
end
end
请注意,其中一个可能的返回分支肯定是与类型签名不匹配。
然而这确实有错误:
defmodule Blog.UserResolver do
@type one_user :: ( {:error, String.t} )
@spec find(%{id: String.t}, any()) :: one_user
# Throws an error since no return path matches the type spec
def find(%{id: id}, _info) do
age = :rand.uniform(99)
if (age < 100) do
{:ok, %{email: "dw@1g.io", name: "Deedub"}}
else
10
end
end
end
在这种情况下,可能的分支的 none 与typespec匹配,而dialyzer说有此错误消息:
web/blog/user_resolver.ex:4: Invalid type specification for function 'Elixir.Blog.UserResolver':find/2. The success typing is (#{'id':=_, _=>_},_) -> 10 | {'ok',#{'email':=<<_:64>>, 'name':=<<_:48>>}}
我不明白的部分是透析器清楚识别分支可能返回的两种不同类型((#{'id':=_, _=>_},_) -> 10 | {'ok',#{'email':=<<_:64>>, 'name':=<<_:48>>}
),所以它不是问题推理。那么为什么它不会认识到其中一个分支不符合类型规范(如果只有一个的分支符合,这似乎很高兴,这根本不是我想要的)< / p>
答案 0 :(得分:6)
在Dogbert提供的LearnYou链接中,dialyzer
将:
只会抱怨可以保证崩溃的类型错误。
在第一个示例中,如果age始终大于或等于100,则函数将返回声明的类型。在第二个示例中,您的函数无法返回声明的类型。
dialyzer
创建一组约束方程。如果对这些方程有任何解决方案,那么透析器就不会抱怨。 Erlang是作为动态类型语言创建的。 dialyzer
只是一个人事后写的程序。由于我确信他们在思考和讨论并理论化的原因,透析器的设计者选择了这种功能。
如果可能,我正在寻找更严格的类型检查器。
到目前为止不可能:
Erlang类型系统
没有更复杂的类型系统的原因是没有 Erlang发明者知道如何写一个,所以它永远不会完成。该 静态类型系统的优点是可以预测错误 编译时而不是在运行时,因此允许故障 早先检测到并以较低的成本固定。很多人都有 试图为Erlang构建一个静态类型系统。不幸的是,由于 Erlang发明时所做的设计决策,没有任何项目 能够写一个全面的类型系统,因为有热代码 装载,这本质上是困难的。引用乔阿姆斯特朗的话 许多类型系统之一的火焰战争,“它似乎应该是 '简单' - 事实上,几周的编程可以制作一个类型系统 处理95%的语言。一些人的工作[由一些人 计算机科学中最聪明的人已经尝试着解决问题 另外5% - 但这真的很难。“
来自“Erlang编程(Francesco Cesarini&amp; Simon Thompson)”。
需要test suite
来控制动态类型的程序。 Elixir只是Erlang的Rubified版本。 Ruby也是一种动态类型的语言 - 但它没有透析器。 Ruby唯一有的就是测试。您可以使用测试套件来控制计算机编程语言的Wild West,而不是编译器。如果你需要一个静态类型的语言,那么一个Rubified版本的Erlang不是一个很好的选择 - 参见Haskell。