26

Lee Naishの論文「 Prologの高階論理プログラミング」で、なじみのないProlog構文に出くわしました。これが論文からの最初のコードサンプルです:

% insertion sort (simple version)
isort([], []).
isort(A.As, Bs) :-
    isort(As, Bs1),
    isort(A, Bs1, Bs).

% insert number into sorted list
insert(N, [], [N]).
insert(N, H.L, N.H.L) :-
    N =< H.
insert(N, H.LO, H.L) :-
    N > H,
    insert(N, LO, L).

私の混乱はでA.Asですisort(A.As, Bs) :-。コンテキストからは、これはリストの代替cons構文であるように見えisort([A|As], Bs) :-ます。これは。と同等です。

同様N.H.Lに言うのがより便利な方法のよう[N|[H|L]]です。

しかし、SWI Prologは、この異常な構文を受け入れません(私が何か間違ったことをしている場合を除きます)。

誰かがそれを認識していますか?私の仮説は正しいですか?どのPrologインタープリターがそれを有効な構文として受け入れますか?

4

3 に答える 3

33

ドット演算子は、Algol-W で書かれた 1972 年の最初の Prolog システムでリストに使用され、Prolog 0 と呼ばれることもありました。これは、LISP システムの同様の表記法に触発されています。次の例は、Prologの作成者である Alain Colmerauer と Philippe Roussel による論文 Thebirth of Prologからのものです。

+ELEMENT(*X, *X.*Y).
+ELEMENT(*X, *Y.*Z) -ELEMENT(*X, *Z).

当時[]NIL.

Battani & Meloni によって Fortran で書かれた次の Prolog バージョンでは、アトムと変数を区別するためにケースが使用されました。その後、DECsystem 10 Prolog では角かっこ表記が導入され、nilandX.Xs[]and[X,..Xs]に置き換えられました。これは、DECsystem 10 の後のバージョンで[X|Xs]代替として使用されました。ISO Prolog では、標準構文として[X|Xs]、 、のみが存在します。.(X,Xs)'.'(X,Xs)

ISO Prolog では、ドットにはさまざまな役割があることに注意してください。それはすでに

  • %または SPACE、NEWLINE、TAB などのレイアウト文字が続く場合の終了トークン。

  • 浮動小数点数の小数点、3.14159

  • グラフィック トークン charとしてグラフィック トークンを形成する=..

したがって.、中置演算子として宣言する場合は、十分に注意する必要があります。あなたが書くものとPrologシステムが読むものの両方で。スペースを 1 つ追加すると、用語の意味が変わる場合があります。両方の表記法で 2 つの数のリストを考えてみましょう。

[1,2.3,4]. [5].
1 .2.3.4.[]. 5.[].

の後にスペースを追加する必要があることに注意してください1。このコンテキストでは、数字の前に空白を追加すると、用語の意味が変わる場合があります。そのようです:

[1|2.3]. [4]. 5. [].
1 .2.3. 4.[]. 5. [].

さらに説得力のある別の例を次に示します。

[1,-2].
1.(-2).[].

負の数には、ドット リスト内の丸括弧が必要です。

現在、.デフォルトで infix を提供しいるのは YAP と XSB だけです。また、XSB は上記のドット構文も認識しません。負でない数値の一部を丸括弧で囲む必要があります。

あなたはN.H.L、より便利な言い方のように見えると書きました[N|[H|L]]。ISO Prolog には、このような式を単純化するための簡単な経験則があります。リスト内でトークンが互いにすぐ後にある場合はいつでも、それらを置き換えることができます|(右側の対応するものを削除します)。したがって、次のように書くことができます。これはそれほど悪くはありません。[,][N,H|L]

そのルールを他の方向にも使用できます。リストがある場合は、次のように「かみそりの刃」として [1,2,3,4,5]使用できます。|[1,2,3|[4,5]]


Naish の論文を読んでいるので、もう 1 つ注意してくださいcall/N。また、ISO Prolog はcall/1call/2最大で をサポートしていcall/8ます。

于 2012-04-05T13:02:09.933 に答える
9

はい、その通りです。ドットはリストコンス中置演算子です。実際には ISO Prolog 標準で必要ですが、通常は隠されています。少し前にその構文を見つけました(そして使用しました):

:- module(eog, []).
:- op(103, xfy, (.)).

% where $ARGS appears as argument, replace the call ($ARGS) with a VAR
% the calle goes before caller, binding the VAR (added as last ARG)
funcs(X, (V, Y)) :-
    nonvar(X),
    X =.. W.As,

    % identify meta arguments
    (   predicate_property(X, meta_predicate M)
        % explicitly exclude to handle test(dcg)
        % I'd like to handle this case in general way...
    ,   M \= phrase(2, ?, ?)
    ->  M =.. W.Ms
    ;   true
    ),

    seek_call(As, Ms, Bs, V),
    Y =.. W.Bs.

% look for first $ usage
seek_call([], [], _Bs, _V) :-
    !, fail.
seek_call(A.As, M.Ms, A.Bs, V) :-
    M @>= 0, M @=< 9, % skip meta arguments
    !, seek_call(As, Ms, Bs, V).
seek_call(A.As, _, B.As, V) :-
    nonvar(A),
    A = $(F),
    F =.. Fp.FAs,
    (   current_arithmetic_function(F) % inline arith
    ->  V = (PH is F)
    ;   append(FAs, [PH], FBs),
        V =.. Fp.FBs
    ),
    !, B = PH.
seek_call(A.As, _.Ms, B.As, V) :-
    nonvar(A),
    A =.. F.FAs,
    seek_call(FAs, Ms, FBs, V),
    !, B =.. F.FBs.
seek_call(A.As, _.Ms, A.Bs, V) :-
    !, seek_call(As, Ms, Bs, V).

:- multifile user:goal_expansion/2.
user:goal_expansion(X, Y) :-
    ( X = (_ , _) ; X = (_ ; _) ; X = (_ -> _) )
    -> !, fail % leave control flow unchanged (useless after the meta... handling?)
    ;  funcs(X, Y).

/* end eog.pl */

私はそれに対して忠告されました。事実上、[A|B] 構文は . 読みやすくするために導入された演算子。

OT : そのコードは何ですか?

上記のコードは、関数で Prolog を甘くしようとする私の試みです。つまり、リクエストに応じて、 を使用し$て、算術式で必要な一時変数 (たとえば) を導入します。

fact(N, F) :-
     N > 1 -> F is N * $fact($(N - 1)) ; F is 1.

各 $ は変数を導入します。拡張後、より伝統的な事実/ 2が得られます

?- listing(fact).
plunit_eog:fact(A, C) :-
    (   A>1
    ->  B is A+ -1,
        fact(B, D),
        C is A*D
    ;   C is 1
    ).

多くの式がある場合、それは役に立つかもしれません...

于 2012-04-05T06:52:44.180 に答える
8

この構文はNU-Prologから来ています。ここを参照してください。これはおそらく通常のリストファンクター'。'/2であり、末尾の空のリストを必要とせずに、中置演算子として再定義されています。

?- L= .(a,.(b,[])).
L = [a,b]
Yes (0.00s cpu)
?- op(500, xfy, '.').
Yes (0.00s cpu)
?- L = a.b.[].
L = [a,b]
Yes (0.00s cpu)
于 2012-04-05T06:22:37.467 に答える