I am just reading about syntax of Erlang, and read this implementation of while loop:
-module(helloworld).
-export([while/1,while/2, start/0]).
while(L) -> while(L,0).
while([], Acc) -> Acc;
while([_|T], Acc) ->
io:fwrite("~w~n",[Acc]),
while(T,Acc+1).
start() ->
X = [1,2,3,4],
while(X).
Is the semicolon a mistake? (4th line: while([], Acc) -> Acc;)
I would write the two functions like this:
while(L) -> while(L,0).
while([], Acc) -> Acc;
while([_|T], Acc) ->
io:fwrite("~w~n",[Acc]),
while(T,Acc+1).
start() ->
X = [1,2,3,4],
while(X).
Using whitespace to separate the function definitions makes it clear that two different functions are being defined: while/1 and while/2.
I had no idea about [_|T]. It just comes after this part in the
tutorial, so that's very confusing.
That's nearly equivalent to [H|T], which deconstructs a list into the Head and the Tail, where the Head is the first element of a list and the Tail is the rest of the list. The variable name _ means that you don't care about the variable, so you will not use it in the function body. In this case, it means that you don't care about the Head of the list, all you want is the Tail of the list. If a named variable is used in the head of a function clause, and you don't use the variable in the body of the function, then the compiler will give you a warning.
Here's an example of how deconstructing a list with pattern matching works:
-module(my).
-compile(export_all).
f([Head|Tail]) ->
io:format("The head of the list is: ~w~n", [Head]),
io:format("The tail of the list is: ~w~n", [Tail]).
In the shell:
8> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
9> my:f([1, 2, 3]).
The head of the list is: 1
The tail of the list is: [2,3]
ok
10>
No. There are two functions defined here: while/1 (one argument) and while/2 (two arguments). The second one have two function bodies; which one to use is decided through pattern matching.
I can't get how I can go through all characters in a string, can you please share a simple example?
I have a string, like
"function(){var a = 10; var b = 5; return a + b;}".
Now I want to "cycle" through the string character by character and do something depending on its value.
Here is my code which doesn't work, while running as lexme("some string here").:
lexme(S) ->
lexme(S, 1).
lexme([H | T], _) ->
io:fwrite("~p~n", [H]),
T.
In order to make lexme/2 recursive, it must call itself.
Try this:
lexme([H | T], _) ->
io:fwrite("~p~n", [H]),
lexme(T, 1).
I'm not sure what you intend to do with the second parameter. You're ignoring it, so why is it there?
You'll also want a function head that deals with the empty list so that the recursion can terminate, so the full definition would be something like this:
lexme([], _) ->
done;
lexme([H | T], _) ->
io:fwrite("~p~n", [H]),
lexme(T, 1).
See http://learnyousomeerlang.com/recursion for more information.
Given any list in Erlang, e.g.:
L = [foo, bar, foo, buzz, foo].
How can I only show the unique items of that list, using a recursive function?
I do not want to use an built-in function, like one of the lists functions (if it exists).
In my example, where I want to get to would be a new list, such as
SL = [bar, buzz].
My guess is that I would first sort the list, using a quick sort function, before applying a filter?
Any suggestions would be helpful. The example is a variation of an exercise in chapter 3 of Cesarini's & Thompson's excellent "Erlang Programming" book.
I propose this one:
unique(L) ->
unique([],L).
unique(R,[]) -> R;
unique(R,[H|T]) ->
case member_remove(H,T,[],true) of
{false,Nt} -> unique(R,Nt);
{true,Nt} -> unique([H|R],Nt)
end.
member_remove(_,[],Res,Bool) -> {Bool,Res};
member_remove(H,[H|T],Res,_) -> member_remove(H,T,Res,false);
member_remove(H,[V|T],Res,Bool) -> member_remove(H,T,[V|Res],Bool).
The member_remove function returns in one pass the remaining tail without all occurrences of the element being checked for duplicate and the test result.
I may do it this way :)
get_unique(L) ->
SortedL = lists:sort(L),
get_unique(SortedL, []).
get_unique([H | T], [H | Acc]) ->
get_unique(T, [{dup, H} | Acc]);
get_unique([H | T], [{dup, H} | Acc]) ->
get_unique(T, [{dup, H} | Acc]);
get_unique([H | T], [{dup, _} | Acc]) ->
get_unique(T, [H | Acc]);
get_unique([H | T], Acc) ->
get_unique(T, [H | Acc]);
get_unique([], [{dup, _} | Acc]) ->
Acc;
get_unique([], Acc) ->
Acc.
I think idea might be: check if you already seen the head of list. If so, skip it and recursively check the tail. If not - add current head to results, to 'seen' and recursively check the tail. Most appropriate structure for checking if you already have seen the item is set.
So,i'd propose following:
remove_duplicates(L) -> remove_duplicates(L,[], sets:new()).
remove_duplicates([],Result,_) -> Result;
remove_duplicates([Head|Tail],Result, Seen) ->
case sets:is_element(Head,Seen) of
true -> remove_duplicates(Tail,Result,Seen);
false -> remove_duplicates(Tail,[Head|Result], sets:add_element(Head,Seen))
end.
Use two accumulators. One to keep elements you have seen so far, one to hold the actual result. If you see the item for the first time (not in Seen list) prepend the item to both lists and recurse. If you have seen the item before, remove it from your result list (Acc) before recursing.
-module(test).
-export([uniques/1]).
uniques(L) ->
uniques(L, [], []).
uniques([], _, Acc) ->
lists:reverse(Acc);
uniques([X | Rest], Seen, Acc) ->
case lists:member(X, Seen) of
true -> uniques(Rest, Seen, lists:delete(X, Acc));
false -> uniques(Rest, [X | Seen], [X | Acc])
end.
unique(List) ->
Set = sets:from_list(List),
sets:to_list(Set).
This solution only filters out duplicates from a list. probably requires building upon to make it do what you want.
remove_duplicates(List)->
lists:reverse(removing(List,[])).
removing([],This) -> This;
removing([A|Tail],Acc) ->
removing(delete_all(A,Tail),[A|Acc]).
delete_all(Item, [Item | Rest_of_list]) ->
delete_all(Item, Rest_of_list);
delete_all(Item, [Another_item| Rest_of_list]) ->
[Another_item | delete_all(Item, Rest_of_list)];
delete_all(_, []) -> [].
EDIT
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Windows\System32>erl
Eshell V5.9 (abort with ^G)
1> List = [1,2,3,4,a,b,e,r,a,b,v,3,2,1,g,{red,green},d,2,5,6,1,4,6,5,{red,green}].
[1,2,3,4,a,b,e,r,a,b,v,3,2,1,g,
{red,green},
d,2,5,6,1,4,6,5,
{red,green}]
2> remove_duplicates(List).
[1,2,3,4,a,b,e,r,v,g,{red,green},d,5,6]
3>
Try the following code
-module(util).
-export([unique_list/1]).
unique_list([]) -> [];
unique_list(L) -> unique_list(L, []).
% Base Case
unique_list([], Acc) ->
lists:reverse(Acc);
% Recursive Part
unique_list([H|T], Acc) ->
case lists:any(fun(X) -> X == H end, T) of
true ->
unique_list(lists:delete(H,T), Acc);
false ->
unique_list(T, [H|Acc])
end.
unique(L) -> sets:to_list(sets:from_list(L)).
The simplest way would be to use a function with an "accumulator" that keeps track of what elements you already have.
So you'd write a function like
% unique_acc(Accumulator, List_to_take_from).
You can still have a clean function, by not exporting the accumulator version, and instead exporting its caller:
-module(uniqueness).
-export([unique/1]).
unique(List) ->
unique_acc([], List).
If the list to take from is empty, you're done:
unique_acc(Accumulator, []) ->
Accumulator;
And if it's not:
unique_acc(Accumulator, [X|Xs]) ->
case lists:member(X, Accumulator) of
true -> unique_acc(Accumulator, Xs);
false -> unique_acc([X|Accumulator], Xs)
end.
2 things to note:
-- This does use a list BIF -- lists:member/2. You can easily write this yourself, though.
-- The order of the elements are reversed, from original list to result. If you don't like this, you can define unique/1 as lists:reverse(unique_acc([], List)). Or even better, write a reverse function yourself! (It's easy).