Erlang推理

ufj5ltwl  于 2022-12-16  发布在  Erlang
关注(0)|答案(2)|浏览(186)

由于Stopover未绑定,以下源代码无法编译。
我是第一次使用Erlang,我该如何重写它?

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

此模块的用法可能是:

path( madrid, moscou ).

并且期望的答案应该是{ km, 3531}

bjp0bcyl

bjp0bcyl1#

由于中途停留未绑定,以下源代码无法编译。
我是第一次使用Erlang,我该如何重写它?
看看这个代码:

-module(a).
-compile(export_all).

do_stuff() ->
    Stopover.

下面是当我试图编译它时发生的情况:
a.erl:5:变量“Stopover”未绑定
变量Stopover从来没有赋值,所以erlang不知道函数do_stuff()应该返回什么,下面我们做一些类似的事情:

path( From, Stopover ) + path( Stopover, To ).

变量FromTo是函数path()的参数变量,在调用了path()时,例如path(madrid, moscow),对变量From赋予madrid,对变量To赋予moscow。你没有给变量Stopover赋值。
您需要将path()重新定义为如下所示:

path(From, To, Stopover) ->

接下来,您应该尝试看看添加元组是否真的有效:

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>

不要!
您需要做的是使用模式匹配从每个元组中提取距离(一个整数),然后将这两个整数相加:

{km, Distance1} = path( From, Stopover ),
...             = path(Stopover, To),

{km, Distance1 + Distance2}.
fnvucqvd

fnvucqvd2#

@7stud已经回答了这个问题,我想知道如何在erlang中实现这样的路径搜索,下面是一个可能的解决方案:

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

它使用一个外部文件来定义“已知距离”,我已经用这个来测试:

{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}.

在 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>

下一步骤可以是每当完成新的请求时增加已知距离的列表。

相关问题