>我有一个项目在代码中没有-spec
或-type
,目前透析器可以找到一些警告,其中大多数是机器生成的代码。
在代码中添加类型规范会使透析器发现更多错误吗?
题外话,有没有工具可以检查是否违反了规范?
添加字体规格将大大提高透析器的准确性。
因为 Erlang 是一种动态语言,所以 Dialyzer 必须默认对类型进行相当广泛的解释,除非你给它提示以缩小它将要经历的"成功"类型。把它想象成给透析器一个过滤器,通过它,它可以将一组可能的成功转换为应该工作的显式类型的子集。
这与 Haskell 不同,其中默认假设是失败,并且必须使用成功的类型编写所有代码才能编译 - Dialyzer 必须默认假设成功,除非它确定某个类型将失败。
字体规格是其中的主要部分,但透析器也检查防护装置,因此像这样的功能
increment(A) -> A + 1.
与
increment(A) when A > 100 -> A + 1.
虽然两者都可以键入为
-spec increment(integer()) -> integer().
大多数时候你只关心整数值是integer()
、pos_integer()
、neg_integer()
或non_neg_integer()
,但偶尔你需要一个只在一侧限定的任意范围——而类型语言目前没有办法表示这一点(尽管我个人希望看到100..infinity
工作的声明(。
when A > 100
的无界范围需要防护装置,但像when A > 100 and A < 201
这样的有界范围可以仅在 typespec 中表示:
-spec increment(101..200) -> pos_integer().
increment(A) -> %stuff.
守卫速度很快,除了呼叫length/1
(你可能实际上永远不会在守卫中需要(,所以在你真正知道并证明你有一个来自守卫的性能问题之前,不要担心性能开销。使用防护装置和排字规格来约束透析器非常有用。它作为文档也非常有用,特别是如果您使用 edoc,因为打字规范将显示在那里,使 API 不那么神秘,一目了然。
有一些关于在现有代码库中使用透析器的有趣文献。这里有一个有据可查的经验:Erlang程序的逐步输入:牧马人体验。(不幸的是,我以前从中学到很多其他链接已经消失或移动。(!.!)仔细阅读牧马人论文,浏览用户指南和手册页,玩透析器,以及像Haskell这样的类型系统的一些先前经验,将为您从Dialyzer中获得大量里程做好准备。
[附带说明一下,我之前已经和一些人谈过指定"纯"函数,这些函数可以通过符号或使用不同的定义语法(可能是 Prolog 的:-
而不是 Erlang 的->
来保证为强类型......或其他什么(,但是虽然那会很酷,而且即使是现在也很有可能将副作用集中在程序的一小部分并将所有结果传递回一个{Results, SideEffectsTODO}
元组,这根本不是一个迫切的需求,Erlang 工作得很好。但透析器确实非常有帮助,可以告诉你你在哪里失去了自己的踪迹!