整数LのリストでXの最小値とYの最大値を見つけるための述語minmax(L、X、Y)の記述方法。
例:
?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10, Y = 7.
整数LのリストでXの最小値とYの最大値を見つけるための述語minmax(L、X、Y)の記述方法。
例:
?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10, Y = 7.
list_minnum_maxnum/3
のように定義しましょうlist_minnum/2
:
list_minnum_maxnum([E|Es],Min,Max) :-
V is E,
list_minnum0_minnum_maxnum0_maxnum(Es,V,Min,V,Max).
list_minnum0_minnum_maxnum0_maxnum([] ,Min ,Min,Max ,Max).
list_minnum0_minnum_maxnum0_maxnum([E|Es],Min0,Min,Max0,Max) :-
V is E,
Min1 is min(Min0,V),
Max1 is max(Max0,V),
list_minnum0_minnum_maxnum0_maxnum(Es,Min1,Min,Max1,Max).
OPによって与えられたサンプルクエリ:
?- list_minnum_maxnum([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.
のこの実装はlist_minnum_maxnum/3
、あらゆる種類の数値で機能することに注意してください。
?- list_minnum_maxnum([1,-10,1,0,7.2,7,7], Min,Max).
Min = -10,
Max = 7.2.
整数の処理のみに関心がある場合は、 clpfdを使用してください。
:- use_module(library(clpfd)).
次のように定義list_zmin_zmax/3
します。
list_zmin_zmax([E|Es],Min,Max) :-
V #= E,
list_zmin0_zmin_zmax0_zmax(Es,V,Min,V,Max).
list_zmin0_zmin_zmax0_zmax([] ,Min ,Min,Max ,Max).
list_zmin0_zmin_zmax0_zmax([E|Es],Min0,Min,Max0,Max) :-
V #= E,
Min1 #= min(Min0,V),
Max1 #= max(Max0,V),
list_zmin0_zmin_zmax0_zmax(Es,Min1,Min,Max1,Max).
前と同じサンプルの使用:
?- list_zmin_zmax([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.
わかった!非整数のサポートについてはどうですか?
?- list_zmin_zmax([1,-10,1,0,7.2,7,7], Min,Max).
ERROR: Domain error: `clpfd_expression' expected, found `7.2'
エラーが発生することを期待していましたが、エラーが発生しました...
clpfdのおかげで、より一般的なクエリも実行できることに注意してください。
?- list_zmin_zmax([A,B], Min,Max).
A #>= Min, Max #>= A, Min #= min(A,B),
B #>= Min, Max #>= B, Max #= max(A,B).
前述のように、リストを反復処理して、最小値と最大値を累積する必要があります。したがって、これをゼロから作成する必要があると仮定すると、最初に行う必要があるのは、問題を簡単な手順に分解することです。
min/3
それはと につながるmax/3
ので、次のようになります。
min(X,X,X).
min(X,Y,X) :- X < Y .
min(X,Y,Y) :- X > Y .
max(X,X,X).
max(X,Y,X) :- X > Y .
max(X,Y,Y) :- X < Y .
ここでの目的のために、必要に応じて、それらを 1 つの述語に結合することもできます。
rank( X , X , X , X ) .
rank( X , Y , X , Y ) :- X < Y .
rank( X , Y , Y , X ) :- X > Y .
Prolog での非常に典型的なプログラミングパターンは、実際の作業を行うプライベートな「ワーカー」述語を呼び出す単純なパブリック API 述語を持つことです。多くの場合、ワーカーの述語は、ジョブを単純化する一時的な「アキュムレータ」変数を保持します。パブリック述語は次のようになります。
minmax([X|Xs],Min,Max) :- minmax_scan( Xs , X , X , Min , Max ).
ここで、パブリック API 述語は空でないリストを受け入れ、ワーカー述語が使用する最小/最大アキュムレータをリストの先頭でシードし、リストの末尾でワーカー述語を呼び出します。
ワーカー述語は次のようになります。
% if the list is empty, we've solved the puzzle, right?
minmax_scan( [] , Min , Max , Min , Max ) .
% if the list is non-empty, we need to compare its head to
% the current value for min/max to determine the new values for min/max
% (which might be the same), and then recurse down on the tail of the list
minmax_scan( [X|Xs] , CurrMin , CurrMax , Min , Max ) :-
min( X , CurrMin , NextMin ) ,
max( X , CurrMax , NextMax ) ,
minmax_scan( Xs , NextMin , NextMax , Min , Max )
.
簡単!
これは複雑で少し複雑です。
is_minmax(A,B-D,C-E) :-
D is min(...),
E is max(...) .
pair(A,B,A-B).
minmax(L,MIN,MAX) :-
L=[A|_], length(L,N), N2 is N-1,
length(L2,N2), append(L2,[MIN],L22),
length(L3,N2), append(L3,[MAX],L33),
maplist(pair, [A|L2], L22, KL2),
maplist(pair, [A|L3], L33, KL3),
maplist(is_minmax, L, KL2, KL3).
(SWI Prolog で動作します)。ドットの代わりに何を書くべきか考えてみてください...
。
リストから最初の値を取得し、リストの他の各要素を調べて、より低い/より高い値を一時的な最小値/最大値として選択します。
リストの最後にある場合、両方を持っています...
minmax([First|Rest], Min, Max) :-
minmax(Rest, First, First, Min, Max).
minmax([], Min, Max, Min, Max).
minmax([Value|Ns], MinCurr, MaxCurr, Min, Max) :-
....
minmax(Ns, MinNext, MaxNext, Min, Max).
再帰呼び出しの前にテストを書かせます (つまり、ドットを埋めます!)。
複数の Prolog システムで利用可能なライブラリ ( aggregate )を指摘するためだけに編集します。
1 ?- [user].
minmax(L, X, Y) :- aggregate( (min(E), max(E)), member(E, L), (X, Y) ).
|:
true.
2 ?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10,
Y = 7.