4

私のコードは実行されますが、問題は同じ結果が複数回表示されることです。これが私のコードです:

disease(hiv,[sore_throat,headache,fever,rash]).
disease(pregnancy,[fatigue,vomiting,light_headedness,increased_waistline]).
disease(flu,[fatigue,fever,tiredness,nasal_discharge]).

diagnose([], []).
diagnose(Name, [H|T]) :-
    disease(The_Disease, Symptoms),
    member(H, Symptoms),
    write(Name), write(' has/is '), writeln(The_Disease),
    diagnose(Name, T).

member(X,[X|_]).
member(X,[_|T]):-
    member(X,T).

プロローグで実行したときの結果:

?- diagnose(kevin,[sore_throat,fatigue,tiredness,rash]).
kevin has/is hiv
kevin has/is pregnancy
kevin has/is flu
kevin has/is hiv
kevin has/is flu
kevin has/is flu
kevin has/is hiv
false.

同じ結果を避けるにはどうすればよいですか?ここで見つけた他の方法を使用してみました:

filter_doubles([], []).
filter_doubles([X|L], Result) :-
    (memberchk(X,L) ->
        filter_doubles(L, Result)
    ;
        filter_doubles(L, Result0),
        Result = [X|Result0]
    ).

しかし、それを自分のコードに適用できませんでした。助けてください。

4

3 に答える 3

7

あなたのプログラムには純粋なコア (医学用語に固執する) がありますが、これは癌性 I/O 組織と絡み合っています! このように正しく行うことは、不可能ではないにしても非常に困難です。たとえば、軽微なエラーとして、プログラムは で失敗しkevinます。しかし、あなたはおそらくそれが成功することを意味していました. 一方、あなたは謎のミスターのために成功するでしょう[]! あれは誰?

それでは、純粋なものと不純なものを分けてみましょう。

プログラムの純粋な部分は、症状のリストを考えられる診断に関連付けることです。あなたの仮定は、病気の徴候の一部である症状が 1 つある場合、その病気を診断するというものです。では、これを と呼んでみませんsymptoms_diagnosis/2か?

symptoms_diagnosis(Symptoms, Diagnosis) :-
   member(Symptom, Symptoms),
   disease(Diagnosis, Indications),
   member(Symptom, Indications).

?- symptoms_diagnosis([sore_throat,fatigue,tiredness,rash], Diagnosis).
Diagnosis = hiv ;
Diagnosis = pregnancy ;
Diagnosis = flu ;
Diagnosis = flu ;
Diagnosis = hiv ;
false.

これ以上苦労しなくても、元のプログラムよりも冗長なソリューションが少ないことに注意してください。では、残りの冗長なソリューションを取り除くにはどうすればよいでしょうか? これはトリックを行います:

?- setof(t,symptoms_diagnosis([sore_throat,fatigue,tiredness,rash], Diagnosis),_).
Diagnosis = flu ;
Diagnosis = hiv ;
Diagnosis = pregnancy.

したがって、冗長なソリューションを取得するときはいつでもsetof(t, ..., _)、目標をラップするだけです。答えがグラウンドアンサーである場合はいつでもそれを使用できます。つまり、答えには変数が残っていません。

たぶん、独自のリストで診断を取得したいですか?

?- setof(Diagnosis,symptoms_diagnosis([sore_throat,fatigue,tiredness,rash],Diagnosis),Diagnoses).
Diagnoses = [flu, hiv, pregnancy].

これで、プリンストン プレインズボロ教育病院の準備が整いました。ハウス博士がプロローグの診断を受け入れないというのは、単なる迷信です!

不純な部分については、@Mog のアプローチをご覧ください。

于 2011-11-29T11:26:34.413 に答える
3

あるいは、次のように書くこともできます:

disease(hiv,[sore_throat,headache,fever,rash]).
disease(pregnancy,[fatigue,vomiting,light_headedness,increased_waistline]).
disease(flu,[fatigue,fever,tiredness,nasal_discharge]).

diagnose(Name, Symptoms) :-
    findall(D, (disease(D, S), intersection(S, Symptoms, I), I \== []), MayGot),
    atomic_concat(Name, ' has/is ', Start),
    maplist(atomic_concat(Start), MayGot, Temp),
    maplist(writeln, Temp).

しかし、Prolog を学習しようとしているのであれば、それはより機能的で Prolog らしくないため、良い考えではありません。

于 2011-11-29T09:40:17.937 に答える
2

症状を確認するときは、すでに収集した病気を覚えておく必要があります。リスト内の疾患を収集 (集計) する必要があり、追加する前にリストに疾患が既に存在するかどうかを確認します。最後にリストを印刷するか、リストに追加された新しい病気ごとに印刷することができます。

私はこのように実装します:

diagnose(Name, Symptoms) :- diagnose0(Name, Symptoms, []).

diagnose0(Name, [], Diseases) :-
    print_diseases(Name, Diseases).
diagnose0(Name, [H|T], DIn) :-
    disease(Disease, Symptoms),
    member(H, Symptoms),
    % you may want to add a cut here to avoid choicepoints
    (
        member(Disease, DIn)
    ->
        diagnose0(Name, T, DIn)
    ;
        DOut = [Disease|DIn],
        diagnose0(Name, T, DOut)
    ).

print_diseases(_Name, []).
print_diseases(Name, [H|T]) :-
    write(Name), write(' has/is '), writeln(H),
    print_diseases(Name, T).

disease/2事実はあなたのコードのとおりです。

これは与える:

?- diagnose(kevin, [sore_throat, fatigue, tiredness, rash]).
kevin has/is flu
kevin has/is pregnancy
kevin has/is hiv
Yes (0.00s cpu, solution 1, maybe more)

次のステップは明らかに、いくつかの診断が特定の症状の代替手段を表していることを表現する方法を見つけ、これらの異なる代替手段から選択することです. クエリに記載されている症状から、Kevin はインフルエンザと HIV に感染しているはずですが、妊娠が Kevin の正しい診断であるとは思えません。これは、 の 2 番目の節に挿入したカットについてのコメントに関連していdiagnose/3ます。カットがなければ、それぞれが一連の症状に一致するさまざまな病気のセットを表す複数の解決策を得ることができます。カットを追加すると、最初の解決策(妊娠を含む)のみが得られます。2 番目のソリューションには、インフルエンザと HIV のみが含まれています。

ところで、member/2組み込みの述語であるため、独自に定義する必要はありません。

于 2011-11-29T07:24:43.960 に答える