2

在这种情况下,Dialyzer 的行为对我来说相当奇怪,我还没有找到任何可以更好地理解它的东西。

这不是错误:

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

在这种情况下,没有任何可能的分支与 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>>}),所以这不是推理的问题。那么为什么它不承认其中一个分支不符合类型规范(如果只有一个分支符合,这似乎很高兴,这根本不是我想要的)

4

1 回答 1

7

从 Dogbert 提供的LearnYou链接中,dialyzer将:

只抱怨会导致崩溃的类型错误。

在您的第一个示例中,如果年龄始终大于或等于 100,则您的函数将返回声明的类型。在第二个示例中,您的函数无法返回声明的类型。

dialyzer创建一组约束方程。如果这些方程有任何解,那么透析器就不会抱怨。Erlang 是作为一种动态类型语言创建的。dialyzer只是有人事后编写的程序。出于我确信他们深思熟虑、讨论和理论化的原因,dialyzer 的设计者选择了该功能。

如果可能的话,我正在寻找更严格的类型检查器。

到目前为止不可能:

Erlang 类型系统

没有更精细的类型系统的原因是 Erlang 的发明者都不知道如何编写类型系统,所以它从未完成。静态类型系统的优点是可以在编译时而不是在运行时预测错误,因此可以更早地检测到错误并以较低的成本进行修复。许多人尝试为 Erlang 构建静态类型系统。不幸的是,由于在 Erlang 发明时做出的设计决定,没有一个项目能够编写一个全面的类型系统,因为热代码加载,这本质上是困难的。引用乔·阿姆斯特朗 (Joe Armstrong) 在众多类型系统的激烈战争之一中的话,“看起来它应该是‘容易的’——事实上,几周的编程就可以创建一个处理 95% 语言的类型系统。

来自“Erlang Programming (Francesco Cesarini & Simon Thompson)”。

需要Atest suite来控制动态类型的程序。Elixir 只是 Erlang 的 Rubified 版本。Ruby 也是一种动态类型语言——但它没有透析器。Ruby 唯一的功能就是测试。您使用测试套件来控制计算机编程语言的狂野西部——而不是编译器。如果您需要一种静态类型的语言,那么 Erlang 的 Rubified 版本不是一个很好的选择——请参阅 Haskell。

于 2017-06-05T01:51:05.633 回答