How to use closures in Erlang? - list

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?

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
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,
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]

Let us look at your function 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.
This function contains statement that is the definition of a function. This being the last statement it becomes the return value. So the call:
lists:map(count(L, 0), E).
indeed returns a list of functions.
Looking at the definition of the count function, it indeed makes recursive calls to count and might actually work if it was ever called, which it isn't.
We could add one statement to the end of your program to call all the elements of the by changing the call in this way:
numberOfOccurences(L, E) ->
[F(E) || F <- lists:map(count(L, 0), E)].
Or alternatively, if you have a preference for the map function:
numberOfOccurences(L, E) ->
lists:map(fun(F) -> F(E) end, lists:map(count(L, 0), E)).
However these do not run.
mymodule:numberOfOccurences([1,2,"abc",2,1,"abc",4,1,1],
[1,2,3,"abc"]).
** exception error: bad function 4
in function mymodule:'-numberOfOccurences/2-lc$^0/1-0-'/2 (/home/tony/Projects/temp/src/mymodule.erl, line 20)
3>
As a matter of style the code would be easier to reason about if count parameters were passed rather than using closures in this way. Sometimes closures are essential such as when using spawn/1, but this is not one of those cases.
Analysing the problem I agree the first stage is a map, however I suggest counting matching elements is best achieved with a fold. However I will generally substitute a list comprehension for a map call. I just think it looks tidier.
So here is my solution:
-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].
Note pattern matching with the value Key inside the foldl function will result in a shadow variable warning. X =:= Key is used instead.
occurances:count([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
[4,2,0,2]
So having made the code actually work how about putting into a closure so that spawn/1 could be called for example. Let us edit our working code module to make such a closure, and let the closure write the result to standard io so we can see the result.
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>

For the record, you don't need a closure to define count.
In my book, it's much clearer to have an explicit count function, and plug it appropriately.
Edit: I've put list parameter second, to match lists module API.
count(X, [], Acc) -> Acc;
count(X, [X|T], Acc) -> count(T, X, Acc+1);
count(X, [_|T], Acc) -> count(T, X, Acc).
numberOfOccurences(L, E) ->
[count(X, L, 0) || X <- E].

Related

Insert function using foldl/foldr

I have been working on a separate function that returns a list that inserts element x after each k elements of list l (counting from
the end of the list). For example, separate (1, 0, [1,2,3,4]) should return [1,0,2,0,3,0,4]. I finished the function and have it working as follows:
fun separate (k: int, x: 'a, l: 'a list) : 'a list =
let
fun kinsert [] _ = []
| kinsert ls 0 = x::(kinsert ls k)
| kinsert (l::ls) i = l::(kinsert ls (i-1))
in
List.rev (kinsert (List.rev l) k)
end
Im now trying to simplify the function using foldl/foldr without any recursion, but I cant seem to get it working right. Any tips/suggestions on how to approach this? Thank You!
These are more or less the thoughts I had when trying to write the function using foldl/foldr:
foldl/foldr abstracts away the list recursion from the logic that composes the end result.
Start by sketching out a function that has a much similar structure to your original program, but where foldr is used and kinsert instead of being a recursive function is the function given to foldr:
fun separate (k, x, L) =
let fun kinsert (y, ys) = ...
in foldr kinsert [] L
end
This isn't strictly necessary; kinsert might as well be anonymous.
You're using an inner helper function kinsert because you need a copy of k (i) that you gradually decrement and reset to k every time it reaches 0. So while the list that kinsert spits out is equivalent to the fold's accumulated variable, i is temporarily accumulated (and occasionally reset) in much the same way.
Change kinsert's accumulating variable to make room for i:
fun separate (k, x, L) =
let fun kinsert (y, (i, xs)) = ...
in foldr kinsert (?, []) L
end
Now the result of the fold becomes 'a * 'a list, which causes two problems: 1) We only really wanted to accumulate i temporarily, but it's part of the final result. This can be circumvented by discarding it using #2 (foldr ...). 2) If the result is now a tuple, I'm not sure what to put as the first i in place of ?.
Since kinsert is a separate function declaration, you can use pattern matching and multiple function bodies:
fun separate (k, x, L) =
let fun kinsert (y, (0, ys)) = ...
| kinsert (y, (i, ys)) = ...
in ... foldr kinsert ... L
end
Your original kinsert deviates from the recursion pattern that a fold performs in one way: In the middle pattern, when i matches 0, you're not chopping an element off ls, which a fold would otherwise force you to. So your 0 case will look slightly different from the original; you'll probably run into an off-by-one error.
Remember that foldr actually visits the last element in the list first, at which point i will have its initial value, where with the original kinsert, the initial value for i will be when you're at the first element.
Depending on whether you use foldl or foldr you'll run into different problems: foldl will reverse your list, but address items in the right order. foldr will keep the list order correct, but create a different result when k does not divide the length of L...
At this point, consider using foldl and reverse the list instead:
fun separate (k, x, L) =
let fun kinsert (y, (?, ys)) = ...
| kinsert (y, (i, ys)) = ...
in rev (... foldl kinsert ... L)
end
Otherwise you'll start to notice that separate (2, 0, [1,2,3,4,5]) should probably give [1,2,0,3,4,0,5] and not [1,0,2,3,0,5].

number_in_month exercise (Iteration over multiple lists in SML)

I am having two lists in SML, lets say list A [(a,b,c),(d,e,f)] and list B [b,e]. I want to count how many occurrence of each item in B that matches the second element of each triple in A. The output should be 2. Because b and e each occurs once in A.
This is my code so far but my counter is always set to 0 when I move from one element to another in B. I know in Java this will just be a simple double for loop.
fun number_in_months (d : (int * int * int ) list, m : (int) list) =
if null m then 0
else if null d then number_in_months(d, tl m)
else if (#2(hd d)) = (hd m) then 1 + number_in_months (tl d, m)
else number_in_months(tl d, m)
The code is not accumulating a value between recursive calls. There may be other logic errors too.
Accumulating a value using recursion and functions is a common pattern which you can read more about here. It's essence is to deconstruct a list using head and tail until the list is empty and accumulate some value at each call. The sum function below is a simple example to show this. This could be adapted to your example to accumulate acc when b or e are found in list A.
fun sum(numbers: (int) list) =
let fun sumR(numbers: (int) list, acc: int) =
if null numbers
then acc
else
sumR(tl numbers, hd numbers + acc)
in
sumR(numbers, 0)
end
Running on [1,2,3] gives:
val sum = fn : int list -> int
- sum([1,2,3]);
val it = 6 : int
Note I am intentionally vague with this answer since this is a question regarding Coursera homework for the Programming Languages class.
As you mention, it would be a nested/double loop in any imperative programming language. What you are actually missing is the second loop.
Your "inner" loop goes through all elements of d, and when this is done, your "outer" loop tries to pop the top element of m and start all over, as seen from this line of your code:
else if null d then number_in_months(d, tl m)
However as you can see, you have just tested the list d to be empty and you supply this (exact same list) to your recursive call on the tail of m, which will then fall in this same case for each successive call until m is also empty and you return 0.
Thus what you are missing is to "keep a copy" of the original input list m. This can be done in various ways, but an inner (helper) function is properly the most used one and it even "looks" like a nested loop
fun number_in_months (d, m) =
let
fun nim' ([], y::ys) = nim (d, ys) (* 1 *)
| nim' (_, []) = 0 (* 2 *)
| nim' ((_, x2, _) :: xs, yss as (y::ys)) = ... (* 3 *)
in
nim'(d, m)
end
Using pattern matching the above code gets much simpler and less error prone. In case 1, the "inner" loop has gone through all elements in d, thus the recursive call using d from the outer function which is not changed at any time. In case 2, the "outer" loop has gone through all elements of m and we return 0 (the neutral element of addition). In case 3 we do the actual work. Here pattern matching is used such that we don't need to enforce the type of the argument and we don't need to pull out the 2nd element of the triple, we already have it in the variable x2. All that is needed is to do the computation and make a recursive call with xs and yss.
When doing it this way, the inner (helper) function is using a "copy" of the original input list d and stepping through its elements (potentially modifying it), but we always got a reference to the original input list, which we can use if/when needed.

Less than function in SML

I've come across 2 confusing problems in SML and was hoping someone could help me out:
The first is a function which takes an element and a list and decides whether that element exists in the list or not, here is the code I've attempted to write:
fun member (e,L) = foldl (fn(a,b) => if (e = b) then true else false) false L;
But I get bool * 'a list --> bool but what I need is ''a * ''a list --> bool
As for the second, it also requires an element and a list but returns a list of elements less than the passed one. I'm not sure whether this should be done via map or foldr/foldl.
Any suggestions?
Thanks in advance :)
Regarding the first question, in fn (a, b) => ... a is the next element and b is the accumulator. Since you compare e with b, e is infered to have type bool. You should compare e with a, and never override b when it becomes true:
fun exists (e, L) =
foldl (fn (a, b) => e = a orelse b) false L
For the second question, you can use foldr/foldl to do so. It's similar to the first example; you start with empty list as the accumulator and prepend an element to it whenever that element is smaller than a threshold.
As a tradeoff, foldr gives you the right order but it isn't tail-recursive. On the other hand, foldl is tail-recursive but gives resulting lists in a reverse order.
to see if an element is in list or not try this:
fun elementExist(e, nil) = false
| elementExist(e, x::xs) = if e = x orelse elementExist(e, xs) then true else false;
for the second one to remove the existing element from the list:
fun elFromList(e, nil) = []
| elFromList(e, x::xs) = if e = x then elFromList(e, xs) else x::elFromList(e, xs);
Good Luck!!

returning the max of a list

I am trying to return the max of a list.
I have the following code
list_max([]) ->
[];
list_max([H|T]) ->
list_max(H, T).
list_max(Temp, []) ->
Temp;
list_max(Temp, [H|T]) when H > Temp ->
Temp = H;
list_max(Temp, T).
But am struggling to relate to Erlang.
How do I assign something to temp and replace it to the highest?
Erlang is one of those languages in which I find it easier to show than to explain.
list_max([] ) -> empty;
list_max([H|T]) -> {ok, list_max(H, T)}.
list_max(X, [] ) -> X;
list_max(X, [H|T]) when X < H -> list_max(H, T);
list_max(X, [_|T]) -> list_max(X, T).
and call it thus:
{ok, Max} = list_max(MyList).
Sorry, maybe I'm missing something. Are you looking for:
lists:max(List). %% Find the max in List
How do I assign something to temp and replace it to the highest?
The short answer is that you can't. Variables in Erlang cannot be changed once assigned.
The slightly longer answer is that, while you can't change a variable inside a particular function call, you can always self-recurse. Tail-recursion in Erlang is optimized.
In the example code that you provided, list_max will only ever look at the first two elements of the list. The fourth and fifth clauses should each call list_max again, with the new value of Temp in the first parameter. This is a common thing to do in functional languages. In this case, Temp is known as an Accumulator (I often name the variable Acc to reflect this use, but of course you can name it whatever you want).
Let me show another solution that could be seen as "in between" Macelo's answer and stmi's answer:
list_max( [H|T] ) -> list_max( H , T ).
list_max( X , [] ) -> X;
list_max( X , [H|T] ) -> list_max( erlang:max(H, X) , T ).
(I also ditched the clause that detects the empty list, because I don't think it really buys you much - though it will now throw an exception if you call it with an empty list.)
Erlang is a single assignment so you cannot change "variables". You can only create new ones.
My recommendation is to look at the lists module. Inside lists.erl you will find:
max([H|T]) -> max(T, H).
max([H|T], Max) when H > Max -> max(T, H);
max([_|T], Max) -> max(T, Max);
max([], Max) -> Max.
You don't update the Max variable (Temp in your example), but rather call the function with the new value or return it from the function.
Easy peasy... :-)
You can also express than in built in functions:
-module(list_max).
-compile(export_all).
list_max([]) -> none;
list_max([H | T] = List) ->
lists:foldl(fun erlang:max/2, H, T);
list_max(_) -> badarg.

How can I write Erlang's list concatenate without using the lists module?

The book I'm reading about Erlang has exercises in the back of it and one is to re-create the lists:append function.
I could do this simply using the ++ operator, but isn't this really slow? And I think the point of the exercise is to do it using list operations that I write.
So far the only approach that I could think of is to do something like:
concat([], _, Results)->
Results;
concat(_, [], Results)->
Results;
concat([Ah|At],B,Results) ->
concat(At,B,[Ah|Results]).
But I know this is incorrect...
Any suggestions on how to go about doing this?
EDIT: To clarify the question, here is an example input and output:
Input: [[1,2,3],[],[4,5],[6]]
Output: [1,2,3,4,5,6]
After working a while, I came up with this code as well:
append([A|[B|[T|[]]]]) ->
append([A++B|T]);
append([H|T]) ->
H++T.
However, this only works for when the list is size 3. How can I modify this so that it works for any given amount of randomly sized lists?
++ is only slow when used wrongly, used carefully it is as fast as anything you could craft by hand. You have to make sure you work through the list in the correct direction, otherwise the resulting append is O(N^2). When we do X ++ Y, we must make a copy of X and then prepend it to Y which is not copied.
In this function, the accumulator appears on the left hand side of the ++, so the append is not efficient.
concatl(Lst) ->
concatl(Lst, []).
concatl([], Acc) ->
Acc;
concatl([H|T], Acc) ->
concatl(T, Acc ++ H).
This function performs much better, even though it's not tail recursive.
concat([]) -> [];
concat([H|T]) ->
H ++ concat(T).
In this case rewriting to be tail recursive is only a modest improvement:
concat2(Lst) ->
concat2(lists:reverse(Lst), []).
concat2([], Acc) -> Acc;
concat2([H|T], Acc) ->
concat2(T, H ++ Acc).
The timings on a big input list show just how huge the improvement is. (Times are in microseconds.)
41> Time(fun() -> test:concatl([lists:seq(1,1000) || X <- lists:seq(1,1000)]) end).
14539061
40> Time(fun() -> test:concat([lists:seq(1,1000) || X <- lists:seq(1,1000)]) end).
245356
42> Time(fun() -> test:concat2([lists:seq(1,1000) || X <- lists:seq(1,1000)]) end).
211571
You only need two parameters to your concat function, as you'll be appending to one of the parameters and that's what you'll eventually return. Something like (untested):
concat(L,[]) ->
L;
concat(L,[H|T]) ->
concat(L ++ [H],T).
The ++ is the append operator, you're going to have to do that to be efficient.
(The idea of the above is to return the left parameter if we've no more left, or call again after moving one of the elements from the right to the left). There's probably more efficiencies around doing the append in reverse and then finally reversing the answer but hey...)
(Just saw your edit, and mine of course only works for two things to append, but you can recurse through the above function for each element in your list of lists...)
One neat approach is to use lists:foldr,
concat(A,B) ->
lists:foldr(fun(X,XS) -> [X|XS] end, B, A).
concat(XS) ->
lists:foldr(fun concat/2, [], XS).
It's also a good excercise to write your own foldr function...
-module(functional).
-export([my_append/2,helper/2]).
my_append(L1,L2) ->
% concatenates lists L1 and L2
functional:helper(lists:reverse(L1),L2).
helper(L1,L2) ->
if
L1 == [] -> L2;
L2 == [] -> L1;
true -> [H1|T1] = L1,
functional:helper(T1,[H1|L2])
end.