2016-03-25 20 views
3

私はPrologに技術的に '返品'がないことを知っていますが、そうでなければ質問を策定する方法を知りませんでした。Prolog - アルゴリズムで印刷する代わりに結果を返す

メトロステーション間のルートを見つけるためのアルゴリズムのサンプルコードが見つかりました。それはうまく動作しますが、結果を印刷して拡張するのが難しくなるか、例えばfindall/3を実行することになっています。

% direct routes 
findRoute(X,Y,Lines,Output) :- 
    line(Line,Stations), 
    \+ member(Line,Lines), 
    member(X,Stations), 
    member(Y,Stations), 
    append(Output,[[X,Line,Y]],NewOutput), 
    print(NewOutput). 

% needs intermediate stop 
findRoute(X,Y,Lines,Output) :- 
    line(Line,Stations), 
    \+ member(Line,Lines), 
    member(X,Stations), 
    member(Intermediate,Stations), 
    X\=Intermediate,Intermediate\=Y, 
    append(Output,[[X,Line,Intermediate]],NewOutput), 
    findRoute(Intermediate,Y,[Line|Lines],NewOutput). 

lineは、アトムとステーションを含むリストを持つ述語です。元の場合
line(s1, [first_stop, second_stop, third_stop])

だから私は11行目でそのprintを取り除くされませんし、後で使用するために結果を格納するために、私のルールに余分な変数を追加しようとしています何。しかし、私は悲惨に失敗しました。何をしようとしても無限ループに入るか、偽を返します。

今:

?- findRoute(first_stop, third_stop, [], []). 
% prints [[first_stop,s1,third_stop]] 

が欲しい:あなたのような

?- findRoute(first_stop, third_stop, [], R). 
% [[first_stop,s1,third_stop]] is stored in R 
+1

あなたは本当に 'findRoute/4'に新しい引数を追加し、' print(newOutput) 'を取り除くだけです。明らかに、述語でまだ使用されていない新しい引数の名前を選択します。 – lurker

答えて

3

を、私はまた、彼らは悪い書籍や他の材料を使用している場合は特に、Prologの初心者の間で頻繁にこのパターンを参照してください。

solve :- 
    .... some goals ... 
    compute(A), 
    write(A). 

上記のほとんどすべての行に問題があります。理由は次のとおりです。

  1. "solve"は、命令番号です。述語をいくつかの方向で使うことができるので、これはPrologのような宣言的言語で意味をなさない。
  2. "計算"も必須です。
  3. write/1は副作用であり、その出力はシステム端末でのみ利用可能です。これにより、実際にはのテストという簡単な方法はありません。

    このようなパターンは常に単純になっているはずです

solution(S) :- 
    condition1(...), 
    condition2(...), 
    condition_n(S). 

どこcondition1などは、単にそれがSが解決することの意味を説明し、純粋な目標です。

次いでSのバインディングが自動的にトップレベルにを印刷さ

?- solution(S). 

を問い合わせます。トップレベルにあなたのための印刷をさせてください!あなたのケースでは

は、ストレートフォワード修正があります:単に引数のNewOutputものを作る、そして最終的副作用を削除します。

 
route(X, Y, Lines, Output, NewOutput) :- 
    line(Line, Stations), 
    \+ member(Line, Lines), 
    member(X, Stations), 
    member(Y, Stations), 
    append(Output, [[X,Line,Y]], NewOutput). 

にも注意してください、私はちょうどroute/5に名前を変更したこと述語は、などのテストのために有用である引数はすべて、すでにをインスタンス化されている場合も意味を、作るためのリストを記述する際に、

はまた、あなたは、多くの場合、表記法を使用してから多くの利益になります。

コードは次のようになります。

 
route(S, S, _) --> [].   % case 1: already there 
route(S0, S, Lines) -->   % case 2: needs intermediate stop 
    { line_stations(Line, Stations0), 
     maplist(dif(Line), Lines), 
     select(S0, Stations0, Stations), 
     member(S1, Stations) }, 
    [link(S0,Line,S1)], 
    route(S1, S, [Line|Lines]). 

便利なことに、あなたはそんなにappend/3を必要とせずにリストの連結を記述するためにこれを使用することができます。私は純度と可読性を高めるためにいくつかの変更を加えました。簡単な練習として正確な違いを把握しています。あなたが使用して、DCGインターフェース述語phrase/2を使用して、これを呼び出す

Rsが見つかったルートをある
?- phrase(route(X,Y,[]), Rs). 

。また、私は経路のリンクを示すために、形式link/3の条件を使用しています。アリティが分かっている場合は、専用の用語を使用することをお勧めします。例えば、あなたが表現する必要のある要素の数があらかじめ分からなければ、リストは良い例です。

+0

答えをありがとう、私は初心者ですが、私はまだそれを修正する方法を知りません。あなたの最初の例と同じことを試みました: '' 'route(X、Y、Lines、Output、NewOutput): - ' ''しかし、私は5つの引数で2番目のケースを '更新'する方法を知らない。 – skamsie

+2

DCGバージョンでは、それほど多くの変数について考える必要はないので、まっすぐに進むことをお勧めします。プレーンなPrologのバージョンでは、2番目の節を新しい変数、例えば 'Route'で拡張し、' route'の再帰呼び出しをまったく同じ変数で拡張することができます。この変数はスレッド化されたものだと考えることができ、後でトップレベルでルートを報告することができます。ただし、このようにタスクを解決するには、 'append/3'があまり必要なので、どのような場合でも非常に困っています。 DCGによって 'append/3'を使わなくてもできます。より効率的な**と**より読みやすい! – mat

+0

はい、あなたは正しいです...私はそれがとても簡単だとは信じられません。私は似たようなものを試してみたに違いないが、プロローグがちょうどfalseを返していたいくつかのタイプミスでつまずいた。この時点では、dcgの表記法はかなり進んでいますが、それにも感謝しています。 – skamsie

関連する問題