The following source doesn't compile because Stopover is unbound.
I'm new to Erlang, how can I rewrite it?
-module(distances).
-export([ path/2 ]).
path( madrid, paris ) ->
{ km, 1049 };
path( paris, moscou ) ->
{ km, 2482 };
path( moscou, berlin ) ->
{ km, 1603 };
path( From, To ) ->
path( From, Stopover ) + path( Stopover, To ).
The usage of this module maybe:
path( madrid, moscou ).
And the epected answer should be { km, 3531}.
The following source doesn't compile because Stopover is unbound.
I'm new to Erlang, how can I rewrite it?
Look at this code:
-module(a).
-compile(export_all).
do_stuff() ->
Stopover.
Here's what happens when I try to compile it:
a.erl:5: variable 'Stopover' is unbound
The variable Stopover was never assigned a value, so erlang has no idea what should be returned by the function do_stuff(). You are doing something similar here:
path( From, Stopover ) + path( Stopover, To ).
The variables From and To are parameter variables for the function path(), and when path() is called, e.g. path(madrid, moscow), then madrid will be assigned to the variable From, and moscow will be assigned to the variable To. Note, however, that nowhere do you assign any value to the variable Stopover.
You need to redefine path() to look like this:
path(From, To, Stopover) ->
Next, you should try to see if adding tuples actually works:
2> {km, 5} + {km, 3}.
** exception error: an error occurred when evaluating an arithmetic expression
in operator +/2
called as {km,5} + {km,3}
3>
Nope!
What you need to do is use pattern matching to extract the distance, an integer, from each tuple, then add the two integers:
{km, Distance1} = path( From, Stopover ),
... = path(Stopover, To),
{km, Distance1 + Distance2}.
This question is already answered by #7stud, and I was wondering how to implement such a path search in erlang. Here is a possible solution:
-module(distances).
-export([ path/2,getTowns/0,start/1, stop/0 ]).
path(From,To) ->
Paths = getPath(),
path(From,To,maps:get(orderedTuple(From,To), Paths, not_found),Paths).
% distanceServer in charge to keep the liste of known distances
% server interfaces
start(Towns) ->
{ok,List} = file:consult(Towns),
Paths = lists:foldl(fun({A,B,D},Acc) -> maps:put(orderedTuple(A,B), D, Acc) end,#{},List),
start(Paths,distance_server).
stop() ->
distance_server ! stop.
getTowns() ->
K = maps:keys(getPath()),
L = lists:usort(lists:flatten([[A,B] || {A,B} <- K])),
io:format("list of towns :~n~p~n~n",[L]).
getPath() ->
distance_server ! {getPath,self()},
receive
Path -> Path
end.
% server fuctions
start(Paths,Server) ->
Pid = spawn(fun() -> distanceServer(Paths) end),
register(Server, Pid).
distanceServer(Path) ->
receive
stop -> stop;
{getPath,From} ->
From ! Path,
distanceServer(Path)
end.
% Searching path
path(From,To,not_found,Paths) -> % if not in the known list, seach for the shortest path
{KM,P} = searchBestPath({0,[From]},To,maps:keys(Paths),{no_dist,no_path}),
case P of
no_path -> not_found;
_ -> {lists:reverse(P),KM}
end;
path(From,To,KM,_) -> % else give the result. Assumption: the known path contains always the best one.
{[From,To],KM}.
searchBestPath({N,[To|_]}=Path,To,_,{BestD,_}) when N < BestD -> Path; % keep the new path if it is better
searchBestPath({N,_},_,_,{BestD,_}=Best) when N >= BestD -> Best; % cancel search if the path so far is longer or equal to the best found
searchBestPath({D,[H|_]=PathSoFar},To,Remaining,Best) ->
Next = [remove(H,{A,B}) || {A,B} <- Remaining, (A =:= H) orelse (B =:= H)], % list of all possible next steps
case Next of
[] -> Best;
Next -> lists:foldl(
fun(X,Acc) ->
{_,ND} = path(H,X), % will always match
R = Remaining -- [orderedTuple(H,X)], % necessary to avoid possible infinite loop in the first search
searchBestPath({D+ND,[X|PathSoFar]},To,R,Acc) % evaluate path for all possible next steps
end,
Best,Next)
end.
% helpers
orderedTuple(A,B) when B > A -> {A,B};
orderedTuple(A,B) -> {B,A}.
remove(X,{X,B}) -> B;
remove(X,{A,X}) -> A.
it uses an external file to define the "known distances", I have used this one for test:
{paris,lyon,465}.
{lyon,marseille,314}.
{marseille,nice,198}.
{marseille,toulouse,404}.
{toulouse,bordeaux,244}.
{bordeaux,paris,568}.
{bordeaux,nantes,347}.
{nantes,paris,385}.
{paris,lille,225}.
{paris,strasbourg,491}.
{lille,strasbourg,525}.
{lille,bruxelles,120}.
{rennes,brest,244}.
{rennes,paris,351}.
{rennes,nantes,113}.
and the result in the shell:
1> c(distances).
{ok,distances}
2> distances:start("distances.txt").
true
3> distances:getTowns().
list of towns :
[bordeaux,brest,bruxelles,lille,lyon,marseille,nantes,nice,paris,rennes,
strasbourg,toulouse]
ok
4> distances:path(bordeaux,bruxelles).
{[bordeaux,paris,lille,bruxelles],913}
5> distances:path(nice,bruxelles).
{[nice,marseille,lyon,paris,lille,bruxelles],1322}
6> distances:path(moscou,paris).
not_found
7> distances:stop().
stop
8>
next step could be to increase the list of known distances each time a new request is done.
Related
Im working on some erlang functions and im also not allowed to use library functions. I have to define a function that drops every other element from a list, starting with the first element.
I have worked on something similar before but i could use BIFs and now i am struggling.
For example, alternate([1,2,3,four,5,6]) is [2,four,6]. I am not sure how to implement it.
spec drop_word(string()) -> string().
drop_word([]) -> [];
drop_word([O|Op]) -> case wsp(O) of
true -> Op;
false -> drop_word(Op)
end.
alternate(List) ->
alternate(List, _Index=0).
alternate([_|T], Index) when Index rem 2 == 0 -> %even indexes
alternate(T, Index+1);
alternate([H|T], Index) when Index rem 2 == 1 -> %odd indexes
[H | alternate(T, Index+1)];
alternate([], _Index) ->
[].
In the shell:
12> a:alternate([1,2,3,four,5,6]).
[2,four,6]
13> a:alternate([1,2,3,four,5]).
[2,four]
But, that can be simplified to:
alternate(List) ->
evens(List).
evens([_|T]) ->
odds(T);
evens([]) -> [].
odds([H|T]) ->
[H | evens(T)];
odds([]) -> [].
In the shell:
6> a:alternate([1,2,3,four,5,6]).
[2,four,6]
7> a:alternate([1,2,3,four,5]).
[2,four]
Here's an accumulator version:
alternate(List) ->
evens(List, []).
evens([_|T], Acc) ->
odds(T, Acc);
evens([], Acc) ->
lists:reverse(Acc).
odds([H|T], Acc) ->
evens(T, [H|Acc]);
odds([], Acc) ->
lists:reverse(Acc).
In the shell:
20> a:alternate([1,2,3,four,5,6]).
[2,four,6]
21> a:alternate([1,2,3,four,5]).
[2,four]
Note that lists:reverse() is highly optimized, so you would never do List ++ [X] many times, which traverses the whole list every time you add an element to the end of the list. Rather, you should always choose to add an element to the head of a list, then call lists:reverse(). Oh yeah, no library functions...a reverse() function is easy to implement yourself, and although it won't be optimized like the erlang version, it will still be more efficient than doing List ++ [X] multiple times.
You can use two atoms drop and keep two match the alternating clauses of do_alternate. Details below in comments.
-module(so).
-export([alternate/1]).
% The exported function starts the actual function and tells it to match the `drop`
% clause. Kept elements of L will be collected in the third argument.
alternate(L) -> do_alternate(drop, L, []).
% The `drop` clause will call the `keep` clause and pass the tail T and the
% currently collected list Acc. The head H will be dropped.
do_alternate(drop, [_|T], Acc) -> do_alternate(keep, T, Acc);
% The `keep` clause will call the `drop` claues and pass the tail T and the
% currently collected list Acc with the head H prepented to it.
do_alternate(keep, [H|T], Acc) -> do_alternate(drop, T, Acc ++ [H]);
% If the arugment list is empty, return the accumulated list.
do_alternate(_, [], Acc) -> Acc.
Example usage:
> c(so).
{ok,so}
9> so:alternate([1,2,3,4,5,6]).
[2,4,6]
10> so:alternate([1,2,3,4,5,6,seven,eight,nine,ten,eleven]).
[2,4,6,eight,ten]
It seems that you want to drop any elements with position which is even. So you can do it like below:
-module(test).
-compile([export_all,debug_info]).
alternate(L) -> do_alternate(L, 0, length(L)).
do_alternate(_, L, L) -> [];
do_alternate([H|T], N, L) ->
case (N band 1) == 0 of
true -> do_alternate(T, N+1, L);
false -> [H] ++ do_alternate(T, N+1, L)
end.
Result in shell:
1> c(test).
test.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,test}
2> test:alternate([1,2,3,four,5,6]).
[2,four,6]
Moreover, if your List only has integer numbers, so you can use BIF like below:
3> lists:partition(fun(A) -> A rem 2 == 1 end, [1,2,3,4,5,6]).
{[1,3,5],[2,4,6]}
You could pattern match on the list, taking two elements at a time:
alternate([_Odd, Even | T]) ->
[Even] ++ alternate(T);
alternate([]) ->
[].
The specification doesn't say what happens if the list has an odd number of elements, so this function will just crash with a "function clause" error in that case. You could add a third clause to handle that - presumably dropping the last element would be a sensible thing to do:
alternate([_Last]) ->
[];
I have added the code as it stands. It can used on any piece of text I am doing some work in Erlang and I am getting an error message which I have included below.
exception error: no function clause matching string:to_lower({error,[80,75,3,4,20,0,6,0,8,0,0,0,33,0,2020], <<210,108,90,1,0,0,32,5,0,0,19,0,8,2,91,67,111,110,116,
101,110,116,95,84,121,...>>}) (string.erl, line 2084)
in function word_sort:readlines/1 (word_sort.erl, line 17).
I have also included an extract of my code below and I would appreciate if I could get pointers on where I am going wrong.
enter code here -module(word_sort).
enter code here-export([main/1]).
-export([unique/2]).
-export([sort/1]).
-export([readlines/1]).
-export([wordCount/3]).
% ========================================================== %
% Load the file and create a list %
% ========================================================== %
readlines(FileName) ->
io:format("~nLoading File : ~p~n", [FileName]),
{ok, File} = file:read_file(FileName),
Content = unicode:characters_to_list(File),
TokenList = string:tokens(string:to_lower(Content), " .,;:!?~/>'<{}£$%^&()#-=+_[]*#\\\n\r\"0123456789"),
main(TokenList).
% ========================================================== %
% Scan through the text file and find a list of unique words %
% ========================================================== %
main(TokenList) ->
UniqueList = unique(TokenList,[]),
io:format("~nSorted List : ~n"),
SortedList = sort(UniqueList), % Sorts UniqueList into SortedList%
io:format("~nSorted List : "),
io:format("~nWriting to file~n"),
{ok, F} = file:open("unique_words.txt", [write]),
register(my_output_file, F),
U = wordCounter(SortedList,TokenList,0),
io:format("~nUnique : ~p~n", [U]),
io:fwrite("~nComplete~n").
wordCounter([H|T],TokenList,N) ->
%io:fwrite("~p \t: ~p~n", [H,T]),
wordCount(H, TokenList, 0),
wordCounter(T,TokenList,N+1);
wordCounter([], _, N) -> N.
% =============================================================%
%Word count takes the unique word, and searches the original list for occurrences of that word%
%==============================================================%
wordCount(Word,[H|T],N) ->
case Word == H of % checks to see if H is in Seen List
true -> wordCount(Word, T, N+1); % if true, N_Seen = Seen List
false -> wordCount(Word, T, N) % if false, head appends Seen List.
end;
wordCount(Word,[],N) ->
io:fwrite("~p \t: ~p ~n", [N,Word]),
io:format(whereis(my_output_file), "~p \t: ~p ~n", [N,Word]).
%=================================================================================
unique([H|T],Seen) -> % Accepts List of numbers and Seen List
case lists:member(H, Seen) of % checks to see if H is in Seen List
true -> N_Seen = Seen; % if true, N_Seen = Seen List
false -> N_Seen = Seen ++ [H] % if false, head appends Seen List.
end,
unique(T,N_Seen); % calls uniques with Tail and Seen List.
%=================================================================================
unique([],Seen) -> Seen.
sort([Pivot|T]) ->
sort([ X || X <- T, X < Pivot]) ++
[Pivot] ++
sort([ X || X <- T, X >= Pivot]);
sort([]) -> [].
unicode:characters_to_list returned some error.
Variable 'Content' contains error message instead of data.
And string:to_lower() got error message as parameter instead of string.
You need just check what characters_to_list returns to you.
readlines(FileName) ->
io:format("~nLoading File : ~p~n", [FileName]),
{ok, File} = file:read_file(FileName),
case unicode:characters_to_list(File) of
Content when is_list(Content) ->
LCcontent = string:to_lower(Content),
TokenList = string:tokens(LCcontent,
" .,;:!?~/>'<{}£$%^&()#-=+_[]*#\\\n\r\"0123456789"),
main(TokenList);
Err ->
io:format("Cannot read file, got some unicode error ~p~n", [Err])
end.
I am trying to calculate this input:
evaluate({mul,{plus,{num,2},{num,3}},{num,4}}).
and get this as an answer:
20
But I cant get it working, here is my code:
evaluate(List) ->
[Res] = lists:foldl(fun evaluate/2, [], tuple_to_list(List)),
Res.
evaluate({num,X},Stack) -> [X|Stack];
evaluate(plus,[N1,N2|Stack])->[N1+N2|Stack];
evaluate(mul,[N1,N2|Stack])->[N1*N2|Stack];
evaluate([{Optr, Num1, Num2}],Stack) ->
evaluate(Num1,Stack),evaluate(Num2,Stack),evaluate(Optr,Stack).
Can you point out my mistakes and correct me, thank you.
First, define your syntax:
{num,Value} for a number,
{plus,Term1,Term2} for an addition,
{mul,Term1,Term2} for a multiplication,
and so on.
Second, solve individual cases:
evaluate({num,Value}) -> Value;
evaluate({plus,Term1,Term2}) -> evaluate(Term1) + evaluate(Term2);
evaluate({mul,Term1,Term2}) -> evaluate(Term1) * evaluate(Term2).
in the shell:
1> E = fun E({num,Value}) -> Value;
1> E({plus,Term1,Term2}) -> E(Term1) + E(Term2);
1> E({mul,Term1,Term2}) -> E(Term1) * E(Term2)
1> end.
#Fun<erl_eval.30.90072148>
2> E({mul,{plus,{num,2},{num,3}},{num,4}}).
20
3>
Although I used a lot the reverse polish notation, it does not apply in your example. The input should be (for your example) [ 2, 3, plus, 4, mul] and it can be solved like this:
evaluate(plus,[A,B|Rest]) -> [A+B|Rest];
% pop operands,perform the operation and push the result
evaluate(mul,[A,B|Rest]) -> [A*B|Rest];
evaluate(A,Acc) when is_number(A) -> [A|Acc]. % push operand on the stack
evaluate(Exp) -> [Res] = lists:foldl(evaluate/2,[],Exp), Res.
in the shell
22> E = fun E(plus,[A,B|Rest]) -> [A+B|Rest];
22> E(mul,[A,B|Rest]) -> [A*B|Rest];
22> E(A,Acc) -> [A|Acc]
22> end.
#Fun<erl_eval.36.90072148>
23> Eval = fun(Exp) -> [Res] = lists:foldl(E,[],Exp), Res end.
#Fun<erl_eval.6.90072148>
24> Eval([2,3,plus,4,mul]).
20
I am supposed to collect frequencies of characters.
freq(Sample) -> freq(Sample,[]).
freq([],Freq) ->
Freq;
freq([Char|Rest],Freq)->
freq(Rest,[{Char,1}|Freq]).
This function does not work in the right way. If the input is "foo", then the output will be
[{f,1},{o,1},{o,1}].
But I wished to have the output like
[{f,1},{o,2}].
I can't manage to modify element in a tulpe. Can anyone help me out of this and show me how it can be fixed?
a one line solution :o)
% generate a random list
L = [random:uniform(26)+$a-1 || _ <- lists:seq(1,1000)].
% collect frequency
lists:foldl(fun(X,[{[X],I}|Q]) -> [{[X],I+1}|Q] ; (X,Acc) -> [{[X],1}|Acc] end , [], lists:sort(L)).
in action
1> lists:foldl(fun(X,[{[X],I}|Q]) -> [{[X],I+1}|Q] ; (X,Acc) -> [{[X],1}|Acc] end , [], lists:sort("foo")).
[{"o",2},{"f",1}]
quite fast with short list, but the execution time increase a lot with long list (on my PC, it needs 6.5s for a 1 000 000 character text) .
in comparison, with the same 1 000 000 character text Ricardo solution needs 5 sec
I will try another version using ets.
By far the easiest way is to use an orddict to store the value as it already comes with an update_counter function and returns the value in a (sorted) list.
freq(Text) ->
lists:foldl(fun (C, D) -> orddict:update_counter(C, 1, D) end, orddict:new(), Text).
Try with something like this:
freq(Text) ->
CharsDictionary = lists:foldl(fun(Char, Acc) -> dict:update_counter(Char, 1, Acc) end, dict:new(), Text),
dict:fold(fun(Char, Frequency, Acc) -> [{Char, Frequency} | Acc] end, [], CharsDictionary).
The first line creates a dictionary that uses the char as key and the frequency as value (dict:update_counter).
The second line converts the dictionary in the list that you need.
Using pattern matching and proplists.
-module(freq).
-export([char_freq/1]).
-spec char_freq(string()) -> [tuple()].
char_freq(L) -> char_freq(L, []).
char_freq([], PL) -> PL;
char_freq([H|T], PL) ->
case proplists:get_value([H], PL) of
undefined ->
char_freq(T, [{[H],1}|PL]);
N ->
L = proplists:delete([H], PL),
char_freq(T, [{[H],N+1}|L])
end.
Test
1> freq:char_freq("abacabz").
[{"z",1},{"b",2},{"a",3},{"c",1}]
L = [list_to_atom(X) || X <- Str].
D = lists:foldl(fun({Char, _}, Acc) -> dict:update_counter(Char, 1, Acc) end, dict:new(), L).
dict:to_list(D).
I am new to Erlang, I need to spawn two process running add function, then add the
two numbers.
assigned value of Process one and two is showing the process id, I need catch the value.
How can I read the return value of add(N) function in my calc function?
-module(myerl).
-export([calc/1,add/1]).
add(N) ->
N + 5.
calc(L)
pone = spawn( fun() -> add(A) end),
ptwo = spawn( fun() -> add(B) end),
Result = Pone + Ptwo,
io:format("result ~p~n", [Result]).
You need to use message passing. You must send a message back to the calling process with the result. The spawn function returns a PID (process identifier) to the newly spawned process, not the result of its execution.
This example should do what you're expecting:
calc(A, B) ->
Self = self(), % The spawned funs need a Pid to send to, use a closure
POne = spawn(fun() -> Self ! {self(), add(A)} end),
PTwo = spawn(fun() -> Self ! {self(), add(B)} end),
wait_for_response(POne, PTwo, 0).
wait_for_response(undefined, undefined, Sum) ->
Sum;
wait_for_response(POne, PTwo, Sum) ->
receive
{POne, V} -> wait_for_response(undefined, PTwo, Sum + V);
{PTwo, V} -> wait_for_response(POne, undefined, Sum + V)
end.
#Soup d'Campbells' explanation is good. I instinctively did something slightly different which, in a toy way, anticipates some bad behavior with the child processes. Also, I allow the input to be a list of numbers, not just 2.
-module(myerl).
-export([calc/1, add/1]).
calc(NumList) when is_list(NumList)->
Parent = self(),
_Pids = [spawn(fun()-> Parent ! add(ANum) end) || ANum <- NumList],
collect(length(NumList), 0);
calc(_) ->
{error, badarg}.
collect(0, Sum) ->
Sum;
collect(Cnt, Sum) ->
receive
N when is_number(N) ->
collect(Cnt-1, Sum + N);
_Bad -> % returned something that isnt a number
collect(Cnt-1, Sum)
after 1000 -> % died or is too slow
collect(Cnt-1, Sum)
end.
add(N) ->
N + 5.