2017-05-05 11 views
1

私はプロローグの宿題の問題を抱えています。基本的な問題は、3つのリストがあり、それぞれにフレーズと値を含むメンバーがあることです。私はランダムにリストのメンバーを選択し、フレーズを印刷し、少なくとも2つのリストからフレーズを印刷するまで繰り返し、印刷されたフレーズの合計値は少なくとも9です。プロローグリスト操作支援

私はこれまでにやったことがあります:私はプログラムの数十回の繰り返しを経て、SWIのドキュメントとLean Prolog Nowとスタックのオーバーフローを検索しました。このプロセスでは、リストに項目を追加するためにassert()を使用すると、後続の実行で破損が発生し、すべての変数がローカルであり、空のリストに単一の項目を追加してもリストにはなりませんあなたは変数の値を変えることはできません。 私のプログラムは、以下を実行します:ランダムに3つのリストから1つを選択します。そのリストから項目をランダムに取得します。選択した項目のフレーズと値を異なる変数に置き、それらを出力します。

主な問題は、私のリスト操作が機能していないように見えることです。 "append(Usedlist、Z、Usedlist3)"という行は、エラーを投げずにコードの2番目の反復で常に失敗します。さらに、メンバー(Z、Usedlist)は、2回目の繰り返しでランダムにリピートを取得するまれなケースとして機能していないと考えています。しかし、私は不具合がリストに正しく追加されていないということを推測します。

関連するコード(健全性の理由から1つのリストに凝縮)

main :- 
     A is 0, 
     B is 0, 
     C is 0, 
     Num is 0, 
     Usedlist = ["Garbage data1", "More garbage data"], 
     prologwhile(Num, A, B, C, Usedlist). 

    prologwhile(Num, A, B, C, Usedlist) :- Num < 9 , 
    F = [["time of day", 1], ["Season", 5], ["Yesterdays weather", 2], ["Month of last big storm", 2], ["Randomly generated riddle", 9], ["A captcha", 1], ['Current day', 6], ["Tomorrows date", 5]], 

    random_member(Rand, F), 
    nth0(1, Rand, Add), 
    writeln(Rand), 
    nth0(0, Rand, Z), 
    writeln(Usedlist), 
    ( member(Z, Usedlist) -> 
     writeln("Test5"), 
     prologwhile(Num, A, B, C, Usedlist) 
    ; writeln(Rand), 
     writeln(Add), 
     writeln("Test6"), 
     append(Usedlist, Z, Usedlist3), 
     writeln(Z), 
     C3 is 1, 
     Num3 is Num + Add, 
     writeln(Num3), 
     prologwhile(Num3, A, B, C3, Usedlist3) 
    ) 

サンプル出力

[Tomorrows date,5] 
[Garbage data1,More garbage data] 
[Tomorrows date,5] 
5 
Test6 
Tomorrows date 
5 
[time of day,1] 
[Garbage data1,More garbage data|Tomorrows date] 
[time of day,1] 
1 
Test6 
false. 

答えて

3

は、私たちは段階でそれに取り組むみましょう:

1.副作用を排除プログラムを簡略化します。

これらは唯一我々はプログラムについて実行したい推論の邪魔になるので、私は、I/Oを実行すべての目標を排除

  1. :私はあなたのプログラムの以下のストレートフォワードの変化で始まります。
  2. 代わりのC定数で、変数iが単に一定  C直接を使用し、コードの残りの部分で後にのみ使用されX is C。このよう

、我々は得る:

 
main :- 
     prologwhile(0, 0, 0, 0, ["Garbage data1", "More garbage data"]). 

prologwhile(Num, A, B, C, Usedlist) :- 
     Num < 9 , 
     F = [["time of day", 1], ["Season", 5], ["Yesterdays weather", 2], ["Month of last big storm", 2], ["Randomly generated riddle", 9], ["A captcha", 1], ['Current day', 6], ["Tomorrows date", 5]], 
     random_member(Rand, F), 
     nth0(1, Rand, Add), 
     nth0(0, Rand, Z), 
     ( member(Z, Usedlist) -> 
      prologwhile(Num, A, B, C, Usedlist) 
     ; append(Usedlist, Z, Usedlist3), 
      Num3 is Num + Add, 
      prologwhile(Num3, A, B, 1, Usedlist3) 
     ). 

今、読みやすくするために、私は次のよう追加のように変更します。

  • 私は、自分の述語
  • フレーズを考慮します
  • 私は、リストの代わりにのペアを使用しますPhrase-Value
  • 私はパターンを使用し、さらに変数名を伝えます。合計で

、我々は今持っている:上記のスニペットで定義されているよう

 
main :- 
     prologwhile(0, 0, 0, 0, ["Garbage data1", "More garbage data"]). 

prologwhile(Num, A, B, C, Usedlist) :- 
     Num < 9 , 
     phrases(Ps), 
     random_member(Phrase-Value, Ps), 
     ( member(Phrase, Usedlist) -> 
      prologwhile(Num, A, B, C, Usedlist) 
     ; append(Usedlist, Phrase, Usedlist3), 
      Num3 is Num + Value, 
      prologwhile(Num3, A, B, 1, Usedlist3) 
     ). 

phrases(["time of day"-1, 
     "Season"-5, 
     "Yesterdays weather"-2, 
     "Month of last big storm"-2, 
     "Randomly generated riddle"-9, 
     "A captcha"-1, 
     'Current day'-6, 
     "Tomorrows date"-5]). 

今後、私はphrases/1を想定し、その定義に沿って運びません。

 
?- main. 
false. 

はあなたが間違いを見つけやすくするために、私は次の定義を追加し、:私たちは持っているので

2.障害の原因を探す

今プログラムについて、実際の推論が開始され、プログラムに次のように

 
$(Goal) :- 
     portray_clause(Goal), 
     Goal. 

我々はprologwhile/5で、この述語を使用することができます。を

 
prologwhile(Num, A, B, C, Usedlist) :- 
     Num < 9 , 
     phrases(Ps), 
     random_member(Phrase-Value, Ps), 
     ( member(Phrase, Usedlist) -> 
      prologwhile(Num, A, B, C, Usedlist) 
     ; $(append(Usedlist, Phrase, Usedlist3)), 
      Num3 is Num + Value, 
      prologwhile(Num3, A, B, 1, Usedlist3) 
     ). 

現在入手:

 
?- main. 
append(["Garbage data1", "More garbage data"], "A captcha", _). 
append(["Garbage data1", "More garbage data"|"A captcha"], 'Current day', _). 
false. 

だからここで問題です:プログラム全体が失敗した

 
?- append(["Garbage data1", "More garbage data"|"A captcha"], 'Current day', _). 
false 

この目標は、したがって、およびを失敗しました。

あなたは明らかにに次のことを意図:

 
append(Usedlist, [Phrase], Usedlist3) 

すなわち、次の2つのリストの内容ではなく、リストや何か他ののものを追加したいです。それは彼らが良好なパフォーマンスを得るためにを追加する代わりにのリストの前でプリペンド要素にしばしば良い考えであることに注意してください、私たちはこれを書くことができます。

だから、
 
Usedlist3 = [Phrase|Usedlist] 

、全体の述語は次のようになります。

 
prologwhile(Num, A, B, C, Usedlist) :- 
     Num < 9 , 
     phrases(Ps), 
     random_member(Phrase-Value, Ps), 
     ( member(Phrase, Usedlist) -> 
      prologwhile(Num, A, B, C, Usedlist) 
     ; Usedlist3 = [Phrase|Usedlist], 
      Num3 is Num + Value, 
      prologwhile(Num3, A, B, 1, Usedlist3) 
     ). 

か短い:しかし

 
prologwhile(Num, A, B, C, Usedlist) :- 
     Num < 9 , 
     phrases(Ps), 
     random_member(Phrase-Value, Ps), 
     ( member(Phrase, Usedlist) -> 
      prologwhile(Num, A, B, C, Usedlist) 
     ; Num3 is Num + Value, 
      prologwhile(Num3, A, B, 1, [Phrase|Usedlist]) 
     ). 

、我々はまだ持っている:

 
?- main. 
false. 
は、場合によっては述語がべき にホールドを考える、このまだが失敗した理由を参照してください。

 
prologwhile(Num, _, _, _, [_,_|_]) :- Num >= 9. 

はこのように、我々が取得、私たちのプログラムにケースを追加します:私は使用していますか

 
prologwhile(Num, _, _, _, [_,_|_]) :- Num >= 9. 
prologwhile(Num, A, B, C, Usedlist) :- 
     Num < 9 , 
     phrases(Ps), 
     random_member(Phrase-Value, Ps), 
     ( member(Phrase, Usedlist) -> 
      prologwhile(Num, A, B, C, Usedlist) 
     ; Num3 is Num + Value, 
      prologwhile(Num3, A, B, 1, [Phrase|Usedlist]) 
     ). 

注反射のビットの後、次は中それべきホールドケースですパターンマッチングを累積リストに追加して、少なくとも2つの異なるペアからの要素が である場合を検出します。

今、私たちは、最後の持っている:

 
?- main. 
true . 

かなりクールだが、その有用ではないこと。

3.レポートのトップレベル

上の実際の解決策は今、プログラムについてのいくつかのより深い質問をする時間です。たとえば、これらの議論はすべて実際にここで何をしていますか?取得、私たちは単にABCを忘れてみましょう:

 
main :- 
     prologwhile(0, ["Garbage data1", "More garbage data"]). 

prologwhile(Num, [_,_|_]) :- Num >= 9. 
prologwhile(Num, Usedlist) :- 
     Num < 9 , 
     phrases(Ps), 
     random_member(Phrase-Value, Ps), 
     ( member(Phrase, Usedlist) -> 
      prologwhile(Num, Usedlist) 
     ; Num3 is Num + Value, 
      prologwhile(Num3, [Phrase|Usedlist]) 
     ). 

それは全く同じように動作します。一方

 
?- main. 
true . 

を、重要なことは、不足している、すなわちフレーズ我々しているようです実際には を使用しています!それを表す引数がであるを取得しましょう。このような状況において、有用な命名規則は、ペアLs0LsLs0初期リストを示す、とLs我々はトップレベルを報告したい最後の一つです。

「ガベージ」要素を忘れることもできます。

したがって、プログラム全体は次のようになります。

 
solution(List) :- 
     prologwhile(0, [], List). 

prologwhile(Num, Ls, Ls) :- Num >= 9, Ls = [_,_|_]. 
prologwhile(Num, Ls0, Ls) :- 
     Num < 9 , 
     phrases(Ps), 
     random_member(Phrase-Value, Ps), 
     ( member(Phrase, Ls0) -> 
      prologwhile(Num, Ls0, Ls) 
     ; Num3 is Num + Value, 
      prologwhile(Num3, [Phrase|Ls0], Ls) 
     ). 

phrases(["time of day"-1, 
     "Season"-5, 
     "Yesterdays weather"-2, 
     "Month of last big storm"-2, 
     "Randomly generated riddle"-9, 
     "A captcha"-1, 
     'Current day'-6, 
     "Tomorrows date"-5]). 

サンプルクエリ:

 
?- solution(Ls). 
Ls = ["Randomly generated riddle", "Season"] ; 
false. 

あなたはまた、簡単にリストを構築しながら、またはのいずれかで、合計値を報告するこれを拡張することができます簡単な追加ステップ。私は運動としてこれを残します。またprologwhileisnotaseasytoreadのように、例えばusing_underscores_would_beのように注意してください。

+1

ありがとうございました。これはうまくいくようです。 –

+1

@mat:非常に良い説明的な答え、+ s(0)! – tas

+0

私はこれ以上の作業をしてきたので、最後の2つのステップが再びどのように機能するのかを私に説明できますか? A、B、Cを追加する必要がありますが、すべてが失敗することはありません。 –