无法在Erlang中创建规范

时间:2017-09-25 22:16:27

标签: erlang

我正在尝试在Erlang模块中创建一个非常简单的规范,但是我收到了这个错误。

  

未定义函数比较规范/ 2

这是我的代码:

-module(spec_example).
-spec compare(any(), any()) -> less | equal | greater.

-record(heap_node, { item :: any(),
                     children :: [#heap_node{}] }).

-record(priority_queue, { root :: #heap_node{} | nil,
                          comparer :: compare() }).

我无法在此定义比较功能,因为它将作为外部参数提供。我在GitHub中找到了similar examples,我猜它们都运行良好。

我在模块和头文件中都尝试了这个,但错误是一样的。我必须遗漏一些非常基本的东西。

3 个答案:

答案 0 :(得分:5)

您引用的示例是头文件(.hrl),而不是源文件(.erl),并且它们会将文件顶部导入应该以某种方式运行的文件。

这似乎是一种强制执行少数模块的行为方式相同的方式。这让我很困惑,因为这种行为定义正是处理的行为。

另请注意,他们的api.hrl 导入wf.hrl,然后这些是imported all over the place in the project。从我可以看到的那些代码中可以看出,确实没有理由将其定义为行为。 (可能有一个原因,但是看一下代码并不明显......我想不出有理由避免在这种情况下使用行为。)

功能规格

定义函数规范时,需要使用基础函数对其进行批注。所以这一切本身都是非法的:

-spec add(integer(), integer()) -> integer().

但这是合法的:

-spec add(integer(), integer()) -> integer().

add(A, B) ->
    A + B.

使用类型,规格,edoc等的示例:https://github.com/zxq9/zuuid

定义行为

所以“什么是行为?”假设您希望在程序中有一个位置,您可以动态选择要调用的模块,并且您必须期望该模块的行为与其他类似定义的模块的行为方式相同。如果您需要致电foo:frob/2,它应该与bar:frob/2的工作方式完全相同(就类型而言)。因此,我们可以在foo_bar.erl内部的某处编写行为定义,然后将模块foo.erlbar.erl声明为foo_bar类型的行为:

-module(foo_bar).

-callback frob(integer(), inet:socket()) -> ok.

然后......

-module(foo).
-behavior(foo_bar).

frob(A, B) ->
    % ...

如果模块foo缺少指定类型的函数frob/2,则会抛出警告,因为它无法匹配它声明的行为。

这对于简化检查,管理和保持有组织的模块间API兼容性的方式非常有用。另请注意,您可以在模块上定义任意数量的回调,并且可以在模块中声明任意数量的行为。

请参阅:How to create and use a custom Erlang behavior?

答案 1 :(得分:4)

-spec只能键入当前模块中声明的顶级函数,而不能键入作为参数传递给顶级函数或存储在记录中的匿名函数。对于这些,您可以-type使用fun(X) -> Y语法:

-type compare() :: fun((any(), any()) -> less | equal | greater).

-record(heap_node, { item :: any(),
                     children :: [#heap_node{}] }).

-record(priority_queue, { root :: #heap_node{} | nil,
                          comparer :: compare() }).

如果我现在创建一个priority_queue,其中comparer是一个arity函数:

main() ->
  #priority_queue{root = nil, comparer = fun(_) -> equal end}.

并运行Dialyzer,我得到:

Record construction #priority_queue{root::'nil',comparer::fun((_) -> 'equal')} violates the declared type of field comparer::fun((_,_) -> 'equal' | 'greater' | 'less')

答案 2 :(得分:1)

  

我无法在此定义比较功能,因为它将作为外部参数提供。

对于这种情况,您需要-type,正如Dogbert在评论中提到的那样:

-type compare() :: fun((any(), any()) -> less | equal | greater).

-record(priority_queue, { root :: #heap_node{} | nil,
                          comparer :: compare() }).

因为您要描述的类型,而不是模块中名为compare的函数的规范。