2017-12-04 1 views
4

私は、キーストアを管理するリレーショナルプロローグプログラムを書いています。最初のコードは、インターネット上で見つかった講義スライドの一部から取っています(http://people.eng.unimelb.edu.au/pstuckey/book/course.html - 参照:データ構造スライドを参照)。純粋にリレーショナルなプロローグプログラムを書くにあたっては、丁寧に配置されたカットを使用してもよいですか?

このコードでは、同じキーで複数の値を追加することができます。ただし、同じキーと値のペアを2回追加します(例:

?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), lookup(D3, a, X). 
D = [], 
D2 = [p(a, 1)], 
D3 = [p(a, 1), p(a, 1)], 
X = 1 

D3はp(a、1)を2回含む。

これが起こらないように、次のコードを追加しました。バックトラックが代替のaddkey節を見つけられないようにするために、私は最初の節の最後にカットを追加しました。

純粋なリレーショナルプログラムのための公正なゲームか、重複したキーと値のペアが追加されないように、より良い方法です。

newdic([]). 
addkey(D0,K,I,D0) :- lookup(D0, K, I), !. % if the key already do nothing 
addkey(D0,K,I,D) :- D = [p(K,I)|D0]. 
delkey([],_,[]). 
delkey([p(K,_)|D],K,D). 
delkey([p(K0,I)|D0],K,[p(K0,I)|D]) :- 
    dif(K, K0), delkey(D0,K,D). 

これは次のようにつながる:

?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), lookup(D3, a, X). 
D = [], 
D2 = D3, D3 = [p(a, 1)], 
X = 1. 

いいえ、より多くのソリューションが用意されています - プログラムはすぐに戻ります。

任意の提案がはるかに高く評価され、

ダニエル

注:脇のように:私は同じキー異なる値に対して追加した場合、カットは同じのために第2の値を識別するためにバックトラックすることができないことキー:

?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), addkey(D3, a, 2, D4), lookup(D4, a, X). 
D = [], 
D2 = D3, D3 = [p(a, 1)], 
D4 = [p(a, 2), p(a, 1)], 
X = 2 ; 
D = [], 
D2 = D3, D3 = [p(a, 1)], 
D4 = [p(a, 2), p(a, 1)], 
X = 1. 
+0

一度しか成功しないようにするには、 'once(lookup(D0、K、I))'のようなものを使うことができます。 – lurker

+0

現在の回答に本当に満足していますか?結局のところ、あなたは何か違うことを尋ねます。 – false

答えて

3

SWI Prologには、キーと値のペアとアソシエーションを扱うためのライブラリ述部があります。私はあなたの状況に合うかもしれないものを見るために、彼らを注意深く見ていないが、考慮すべきことがある。

独自のソリューションを展開する場合は、再帰的にaddkey/4を書き出すとリレーショナルの動作を維持することができます:キーは一意である場合

addkey([], K, V, [p(K,V)]).    % Add to empty dict 
addkey([p(K,V)|T], K, _, [p(K,V)|T]). % Don't add 
addkey([p(K,V)|T], Kadd, Vadd, [p(K,V)|TK]) :- 
    dif(Kadd, K), 
    addkey(T, Kadd, Vadd, TK). 

この実装が追加されます。あなたが同じ値を指定しても同じキーを試してみると、その値は無視され、同じ辞書を返すことになります(これは通常、キーと値のペアの振る舞いと同じです)。キーと値のペアの一意性を非常に簡単に高めることができます。もちろん、使用しているPrologにはdif/2を含める必要があります。または自分自身をロールバックする必要がありますdif/2。 :)

+0

ありがとうございます。 私は自分自身でリレーショナルプロローグを扱うことに興味がありました。今すぐあなたが言及すると、私はおそらくswi-prologでassocライブラリを使用するように切り替えることになります。これははるかに成熟しており、スケーラビリティにも優れています。 – user2193970

0

あなたが代わりにカットされたif-then-else使用することができます。

addkey(D0,K,I,D0) :- 
    (lookup(D0, K, I) -> 
    D = D0 % if the key already [exists] do nothing 
    ; D = [p(K,I)|D0]). 
+0

ありがとうございました。 これはif-then-elseがリレーショナルとして認定されていますか... – user2193970

+0

カットよりも受け入れやすいです。 –

+3

@ user2193970 "if-then-else"は、カットを使用することと同等であり、その動作において "リレーショナル"ではありません。式 'p1 - > p2; p3'は次のように動作します。 '(p1、!、p2); p3 'となる。視覚的にはより受け入れられるかもしれませんが、行動的にはそれ以上はありません。 if-then-elseのリレーショナルバージョンは['if_/3'](https://stackoverflow.com/questions/27358456/prolog-union-for-a-u-b-u-c/27358600#27358600)です。 – lurker

関連する問題