Erlang中是否可以使用多个匿名函数?

时间:2016-01-07 10:41:59

标签: erlang

我处于这样一种情况:我只能创建分配给变量的匿名函数,如下所示:

Foo = fun(X) -> X end.

我知道如果你在一个模块中,你可以做这样的事情:

foo(X) -> X.
foo(X, Y) -> X + Y.
% i.e. foo(3) = 3, foo(3,4) = 7

我的问题是:这可能是匿名函数吗?

一篇博文(我现在已经遗憾了)让我觉得你可以这样做:

Foo = fun(X) -> X;
         (X, Y) -> X + Y
      end.

但这不起作用,因为我遇到“头部不匹配”错误。

2 个答案:

答案 0 :(得分:5)

简单而正确的答案是不,你不能。这实际上非常合乎逻辑,就像你做的那样

foo(X) -> X.
foo(X, Y) -> X + Y.

您实际上正在创建两个函数:foo/1,一个参数的函数;和foo/2,另一个有两个参数的函数。他们相同foo。这直接映射到匿名函数(funs),因此您需要创建两个不同的函数,一个参数中的一个和两个参数中的另一个。

"头部不匹配"错误是抱怨不同数量的论点。

答案 1 :(得分:2)

你只能模式匹配:

Foo = fun ({x,y}) -> one;
          ({a,b}) -> two
          end

你可以接受一个清单:

Foo = fun ([X])   -> X;
          ([X,Y]) -> {X,Y}
          end

我太好奇了,不去看表演,所以我快速进行基准测试。这远非完美,只是为了表明可能是什么,而且实际上应该计算平均值,标准偏差,平均值,最小值和最大值,但我选择了最少的时间来进行1,000,000次呼叫。

我使用了这段代码:

-module(foo).

-export([run/1, norm1/0, norm2/0, norm3/0, norm4/0, list1/0, list2/0, list3/0, list4/0]).

-define(COUNT, 1000000).


run(F) ->
    T = lists:foldl(
        fun(_,Min) ->
            T = ?MODULE:F(),
            if T < Min -> T; true -> Min end
            end,
        ?MODULE:F(),
        lists:seq(1,99)
        ),
    T
    .

norm1() ->
    Foo = fun(N) -> N * N end,
    {T,_} = timer:tc(fun() ->
        lists:map(fun(A) -> Foo(A) end, lists:seq(1,?COUNT))
        end),
    T
    .

norm2() ->
    Foo = fun(N, M) -> N * M end,
    {T,_} = timer:tc(fun() ->
        lists:map(fun(A) -> Foo(A,A) end, lists:seq(1,?COUNT))
        end),
    T
    .

norm3() ->
    Foo = fun(M, N, M) -> N * M end,
    {T,_} = timer:tc(fun() ->
        lists:map(fun(A) -> Foo(A,A,A) end, lists:seq(1,?COUNT))
        end),
    T
    .

norm4() ->
    Foo = fun(N, M, N, M) -> N * M end,
    {T,_} = timer:tc(fun() ->
        lists:map(fun(A) -> Foo(A,A,A,A) end, lists:seq(1,?COUNT))
        end),
    T
    .

list1() ->
    Foo = fun([N]) -> N * N end,
    {T,_} = timer:tc(fun() ->
        lists:map(fun(A) -> Foo([A]) end, lists:seq(1,?COUNT))
        end),
    T
    .

list2() ->
    Foo = fun([N, M]) -> N * M end,
    {T,_} = timer:tc(fun() ->
        lists:map(fun(A) -> Foo([A,A]) end, lists:seq(1,?COUNT))
        end),
    T
    .

list3() ->
    Foo = fun([_, N, M]) -> N * M end,
    {T,_} = timer:tc(fun() ->
        lists:map(fun(A) -> Foo([A,A,A]) end, lists:seq(1,?COUNT))
        end),
    T
    .

list4() ->
    Foo = fun([_, _, N, M]) -> N * M end,
    {T,_} = timer:tc(fun() ->
        lists:map(fun(A) -> Foo([A,A,A,A]) end, lists:seq(1,?COUNT))
        end),
    T
    .

结果如下:

1> foo:run(norm1).
44820
2> foo:run(norm2).
48959
3> foo:run(norm3).
50328
4> foo:run(norm4).
50402
5> 
5> foo:run(list1).
50463
6> foo:run(list2).
58948
7> foo:run(list3).
60829
8> foo:run(list4).
86604
9> 

性能显然取决于列表的长度,正如人们所期望的那样,因为它必须通过列表工作,并且惩罚大于正常调用。

虽然在大多数情况下,如果它是正确的解决方案,那么性能差异对我来说并不是那么大,至少,如果你不希望你的列表中有太多的参数!