List 如何在Erlang中使用闭包?

List 如何在Erlang中使用闭包?,list,functional-programming,erlang,closures,anonymous-function,List,Functional Programming,Erlang,Closures,Anonymous Function,我有两个列表:L和E。我尝试编写一个函数,它返回另一个列表,其中包含E中元素的L出现次数 -module(mymodule). -export([count/2]). -export([numberOfOccurences/2]). count([Head|Tail], Counter) -> fun(Element) -> if [Head|Tail] == [] -> Counter; Element == Head -> count(Tail,

我有两个列表:L和E。我尝试编写一个函数,它返回另一个列表,其中包含E中元素的L出现次数

-module(mymodule).
-export([count/2]).
-export([numberOfOccurences/2]).

count([Head|Tail], Counter) ->
  fun(Element) -> if
    [Head|Tail] == [] -> Counter;
    Element == Head -> count(Tail, Counter + 1);
    Element /= Head -> count(Tail, Counter)
  end
end.

numberOfOccurences(L, E) -> 
    lists:map(count(L, 0), E).

mymodule:numberofoccurrencess[1,2,“abc”,2,1,“abc”,4,1,1],[1,2,3,“abc”])
应返回
[4,2,0,2]
。但它返回一个包含4个函数的列表。我做错了什么?

这里发生的事情是,如果我们展开这个映射,
count(L,0)
首先被调用,然后产生的乐趣被传递到
列表:map
。当结果fun与
E
的每个成员映射并传递给匿名函数时,大多数元素的返回值是调用
count(Tail,Counter)
的结果,该函数返回一个函数

这里有一个函数的重写版本,可以正常工作。重要的是

  • 我修复了基本情况,否则,当空集传递给
    count()
    时,您可能会遇到匹配错误,更重要的是
  • 在闭包中,为了确保正确的递归,需要调用
    count()
    的返回值,因此我将
    count()
    调用的结果存储到
    F
    中,然后使用传递的元素调用该函数
  • 下面是更新后的模块:

    -module(mymodule).
    -export([count/2]).
    -export([numberOfOccurences/2]).
    
    count([],Counter) ->
        fun(_) -> Counter end;
    count([Head|Tail], Counter) ->
        fun(Element) ->
            if
                Element == Head ->
                    F = count(Tail, Counter + 1),
                    F(Element);
                Element /= Head ->
                    F = count(Tail, Counter),
                    F(Element)
            end
        end.
    
    numberOfOccurences(L, E) ->
            lists:map(count(L, 0), E).
    
    结果:

    > mymodule:numberOfOccurences([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
    [4,2,0,2]
    

    让我们看看你的函数count/2

    count([Head|Tail], Counter) ->
      fun(Element) -> if
        [Head|Tail] == [] -> Counter;
        Element == Head -> count(Tail, Counter + 1);
        Element /= Head -> count(Tail, Counter)
      end
    end.
    
    此函数包含作为函数定义的语句。这是最后一条语句,它将成为返回值。因此,呼吁:

            lists:map(count(L, 0), E).
    
    确实返回函数列表。 看看count函数的定义,它确实会对count进行递归调用,如果调用过它,它实际上可能会工作,但事实并非如此

    我们可以在程序末尾添加一条语句,通过以下方式更改调用来调用的所有元素:

    numberOfOccurences(L, E) ->
            [F(E) || F <- lists:map(count(L, 0), E)].
    
    然而,这些不运行

    mymodule:numberOfOccurences([1,2,“abc”,2,1,“abc”,4,1,1], [1,2,3,“abc”])。 **异常错误:错误的函数4 在函数mymodule中:'-numberofoccurrences/2-lc$^0/1-0-'/2(/home/tony/Projects/temp/src/mymodule.erl,第20行)

    3>

    作为一种风格,如果通过计数参数而不是以这种方式使用闭包,那么代码将更容易推理。有时闭包是必要的,例如在使用spawn/1时,但这不是其中之一

    分析这个问题,我同意第一阶段是一张地图,但是我建议最好通过折叠来计算匹配元素。然而,我通常会用列表理解代替映射调用。我只是觉得它看起来更整洁

    因此,我的解决方案如下:

    -module occurances.
    -export [count/2].
    
    count(Data,KeyList) ->
        [ lists:foldl(
           fun(X,Count) when X =:= Key -> Count+1;
              (_,Count) -> Count
           end,
        0,Data) 
         || Key <- KeyList].
    
    -模块事件。
    -导出[计数/2]。
    计数(数据、密钥列表)->
    [列表:foldl(
    当X=:=键->计数+1时的乐趣(X,计数);
    (u,Count)->Count
    完,,
    0,数据)
    ||钥匙
    乐趣()->
    io:格式(“~p~n”,[count(数据,键列表)])
    结束。
    8> F=发生:关闭([1,2,“abc”,2,1,“abc”,4,1,1],[1,2,3,“abc”])。
    F=发生:关闭([1,2,“abc”,2,1,“abc”,4,1,1],[1,2,3,“abc”])。
    #乐趣
    9> 产卵(F)。
    产卵(F)。
    [4,2,0,2]
    10> 
    
    -module occurances.
    -export [count/2].
    
    count(Data,KeyList) ->
        [ lists:foldl(
           fun(X,Count) when X =:= Key -> Count+1;
              (_,Count) -> Count
           end,
        0,Data) 
         || Key <- KeyList].
    
    make_closure(Data,KeyList) ->
    fun() ->
        io:format("~p~n",[count(Data,KeyList)])
    end.
    
    8> F=occurances:make_closure([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
    F=occurances:make_closure([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
    #Fun<occurances.0.132489632>
    9> spawn(F).
    spawn(F).
    [4,2,0,2]
    <0.107.0>
    10>