Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use closures in Erlang?

I have two lists: L and E. I try to write a function, which returns another list with number of occurences from L for elements in E.

-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:numberOfOccurences[1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]) should returns [4,2,0,2]. But it returns a list with 4 functions. What am I doing wrong?

like image 265
ciembor Avatar asked Jan 17 '13 03:01

ciembor


1 Answers

What's happening here, is, if we unroll this map, count(L, 0) is being called first, then that resultant fun is being passed to lists:map. When that resultant fun is being mapped with each member of E, and being passed to the anonymous function, the return value for most of the elements is the result of calling count(Tail,Counter), which returns a function.

Here's a rewritten version of your functions that works. The big thing is

  1. I fixed the base case, otherwise, you'll likely run into a match error when the empty-set is passed to count(), and more importantly,
  2. In your closure, in order to ensure the proper recursion, you need to call the return value of count(), so I'm storing the result of count() calls into F, then calling that function with the passed element.

So here is the updated module:

-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).

Results:

> mymodule:numberOfOccurences([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
[4,2,0,2]
like image 103
chops Avatar answered Oct 20 '22 04:10

chops