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.
I don't understand erlang very well and for the past number of hours I've been searching up ways to fix this but I can't find any good If statement examples.
I'm trying to use a recursive function to move discs from one hanoi tower to another. However I get the "no true branch found when evaluating an if expression". I understand as far as needing true -> somewhere?
-module(hanoi).
-export([main/1]).
%% Create Towers
main(NumDiscs) ->
TowerA = create_tower(NumDiscs),
TowerB = [],
TowerC = [],
display_towers(TowerA,TowerB,TowerC),
solve(NumDiscs,TowerA,TowerB,TowerC).
%% Add the number of discs inputted to the first tower
create_tower(0) -> [];
create_tower(NumDiscs) when NumDiscs > 0 ->
[NumDiscs] ++ create_tower(NumDiscs - 1).
%% Display all towers
display_towers(A,B,C) ->
io:format("-------------------------\n"),
io:format("Tower A: ~p\n",[A]),
io:format("Tower B: ~p\n",[B]),
io:format("Tower C: ~p\n",[C]).
solve(Disc,TowA,TowB,TowC) ->
if Disc > 0 ->
solve(Disc - 1,TowA,TowB,TowC),
TowBNew = [lists:last(TowA)],
TowCNew = [lists:append(TowC,TowBNew)],
TowANew = [lists:sublist(TowA,length(TowA) - 1)],
display_towers(TowANew,TowB,TowCNew),
solve(Disc - 1,TowANew,TowCNew,TowB)
end.
An if expression in Erlang must have a branch that evaluates to true. I'm guessing that error is thrown when Disc > 0 is false. You need to add a true -> clause to that:
solve(Disc,TowA,TowB,TowC) ->
if Disc > 0 ->
solve(Disc - 1,TowA,TowB,TowC),
TowBNew = [lists:last(TowA)],
TowCNew = [lists:append(TowC,TowBNew)],
TowANew = [lists:sublist(TowA,length(TowA) - 1)],
display_towers(TowANew,TowB,TowCNew),
solve(Disc - 1,TowANew,TowCNew,TowB); % <- note the ';'
true ->
% do something here
end.
Here is my code from a long time ago. Hope this can help you:
main(N)->
towerhanoi(N, a, b, c).
towerhanoi(N, A, C, B)->
case N of
1 ->
change(N, A, C);
_ ->
towerhanoi(N-1, A, B, C),
change(N, A, C),
towerhanoi(N-1 , B, C, A)
end.
change(N, A, C)->
io:format("change disc ~p from tower ~p to tower ~p~n", [N, A, C]).
I am working on some homework and we are supposed to be making a combination function in F#. I have got the factorial function down, but it seems to overflow once I get a big number to use factorial on. (Let's say 20) I understand I can use an int64 or a float, but that would change all the inputs on the code. What data type should I use?
let rec Fact (a:int)=
if (a = 0) then 1 else a*Fact(a-1);;
let combo (n:int) (k:int)=
if (n = 0) then 0 else (Fact n)/((Fact k)*(Fact (n-k)));;
On the code right now, when I do combo 20 5;; it gives me 2147. Which is clearly the wrong answer. I looked at the factorial function and when I put 20 in there it gave me a big negative number. Any help would be much appreciated. Thanks in advance.
First of all, if you want to avoid surprises, you can open the Checked module at the top of your file. This will redefine the numerical operators so that they perform overflow checks - and you'll get an exception rather than unexpected number:
open Microsoft.FSharp.Core.Operators.Checked
As Fyodor points out in the comment, you cannot fit factorial of 20 in int and you need int64. However, your combo function then performs division which will make the result of combo 20 5 small enough to fit into int.
One option is to change Fact to use int64, but keep combo as a function that takes and returns integers - you'll need to convert them to int64 before calling Fact and then back to int after performing the division:
let rec Fact (a:int64) =
if (a = 0L) then 1L else a * Fact(a-1L)
let combo (n:int) (k:int) =
if (n = 0) then 0 else int (Fact (int64 n) / (Fact (int64 k) * Fact (int64 (n-k))))
Now you can call combo 20 5 and you'll get 15504 as the result.
EDIT: As noted by #pswg in the other answer, int64 is also quite limited and so you'll need BigInteger for larger factorials. However, the same method should work for you with BigInteger. You can keep the combo function as a function that returns int by converting back from BigInteger to int.
You simply won't be able to do that with an 32-bit integer (int). A 64-bit integer will get you up to 20!, but will fail at 21!. The numbers just get too big, too quickly. To go any further than that you'll need to use System.Numerics.BigInteger (abbreviated bigint in F#).
The parameter can probably stay as an int to be reasonable, but you need to return a bigint:
let rec Fact (n : int) =
if n = 0 then bigint.One else (bigint n) * Fact (n - 1)
Or to be a little more idiomatic:
let rec Fact = function | 0 -> bigint.One | n -> (bigint n) * Fact (n - 1)
And now, in your Combo function, you'll need to use these bigint's internally for all math (thankfully the integer division is all you need in this case).
let Combo (n : int) (k : int) =
if n = 0 then bigint.Zero else (Fact n) / ((Fact k) * (Fact (n - k)))
If you really wanted to make Combo return an int, you can do that conversion here:
let Combo (n : int) (k : int) =
if n = 0 then 0 else (Fact n) / ((Fact k) * (Fact (n - k))) |> int
Examples:
Combo 20 5 // --> 15504
Combo 99 5 // --> 71523144 (would break if you used int64)
Edit: By rethinking your implementation of Combo you can get some big performance improvements out of this. See this question on Math.SE for the basis of this implementation:
let ComboFast (n : int) (k : int) =
let rec Combo_r (n : int) = function
| 0 -> bigint.One
| k -> (bigint n) * (Combo_r (n - 1) (k - 1)) / (bigint k)
Combo_r n (if (2 * k) > n then n - k else k)
A quick benchmark showed this to be significantly faster than the Fact-based version above:
Function Avg. Time (ms)
Combo 99 5 30.12570
ComboFast 99 5 0.72364
I have the following Erlang code and it is giving the warning as follows, when i try to compile it, but that make sense. function need two arguments, but i need to patten match "everything else" rather x, y or z.
-module(crop).
-export([fall_velocity/2]).
fall_velocity(P, D) when D >= 0 ->
case P of
x -> math:sqrt(2 * 9.8 * D);
y -> math:sqrt(2 * 1.6 * D);
z -> math:sqrt(2 * 3.71 * D);
(_)-> io:format("no match:~p~n")
end.
crop.erl:9: Warning: wrong number of arguments in format call.
I was trying an anonymous variable after io:format, but still it is not happy.
In the format you use ~p. It means -- print value. So you must specify what value to print.
last line of case must be
_ -> io:format("no match ~p~n",[P])
Besides, io:format returms 'ok'. So if P is not x y or z, your function will return 'ok' instead of numeric value. I would suggest to return tagged value to separate correct and error returns. Kind of
fall_velocity(P, D) when D >= 0 ->
case P of
x -> {ok,math:sqrt(2 * 9.8 * D)};
y -> {ok,math:sqrt(2 * 1.6 * D)};
z -> {ok,math:sqrt(2 * 3.71 * D)};
Otherwise-> io:format("no match:~p~n",[Otherwise]),
{error, "coordinate is not x y or z"}
end.
To make the comments to the other answer explicit, this is how I would write that function:
-module(crop).
-export([fall_velocity/2]).
fall_velocity(P, D) when D >= 0 ->
case P of
x -> math:sqrt(2 * 9.8 * D);
y -> math:sqrt(2 * 1.6 * D);
z -> math:sqrt(2 * 3.71 * D)
end.
That is, don't handle the incorrect argument in your case expression. If someone passes foo as an argument, you'll get the error {case_clause, foo} along with a stacktrace that points to this function and its caller. This also means that this function cannot leak incorrect values into the rest of the code as a result of being called with incorrect arguments.
Returning {ok, Result} | {error, Error} as in the other answer is equally valid. You'll need to choose the variant that fits your case best.