2012-04-05 15 views
27

Natknąłem się na nieznaną nieco składnię Prologa w pracy Lee Naisha: Higher-order logic programming in Prolog. Oto pierwsza próbka kodu z papieru:Prolog - nietypowa składnia wierszy dla list

% 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). 

My zamieszanie jest z A.As w isort(A.As, Bs) :-. Z kontekstu, pojawia się jako alternatywna składnia cons dla list, odpowiednik isort([A|As], Bs) :-.

Wygląda na to, że łatwiejszy do wymówienia jest .

Ale SWI Prolog nie zaakceptuje tej nietypowej składni (chyba że robię coś źle).

Czy ktoś to rozpoznaje? czy moja hipoteza jest poprawna? Który interpreter Prolog przyjmuje, że jest to poprawna składnia?

+0

Który Prolog jest używany w pracy? –

+0

Zeskanowałem papier, ale niestety nie znalazłem tam odnośnika! –

+0

Może to być po prostu cukier syntaktyczny –

Odpowiedz

33

Kropka operator został użyty do list w pierwszym systemie Prolog 1972 , napisany w Algol-W, czasami nazywane Prolog 0. Inspiruje go podobny zapis w systemach LISP. Następujący przykład pochodzi z gazety The birth of Prolog autorstwa Alaina Colmerauera i Philippe'a Roussela – samych twórców Prolog.

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

Wówczas [] kiedyś NIL.

Następna wersja Prolog napisana w Fortranie przez Battani & Meloni, używane do rozróżniania atomów i zmiennych.Następnie DECsystem 10 Prolog wprowadził notację nawiasów kwadratowych, zastępując nil i , które w późniejszych wersjach DECsystem 10 otrzymały jako alternatywę [X|Xs]. W ISO Prolog jest tylko [X|Xs], .(X,Xs) i jako kanoniczna składnia '.'(X,Xs).

Należy pamiętać, że kropka ma wiele różnych ról w ISO Prolog. Służy ona już jako

  • końca tokena kiedy następuje znak % lub układ jak przestrzeń, linią, TAB.

  • punkt dziesiętny w liczbę zmiennoprzecinkową, jak 3.14159

  • graficzny znak char tworząc znaki graficzne jak =..

więc jeśli teraz deklarując . jako operator Infix , musisz być bardzo ostrożny. Zarówno z tym, co piszesz, jak i jakie systemy Prolog czyta. Pojedyncza dodatkowa przestrzeń może zmienić znaczenie terminu. Rozważmy dwa wykazy numerów w obu zapisów:

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

Należy pamiętać, że trzeba wstawić spację po 1. W tym kontekście dodatkowa biała spacja przed numerem może zmienić znaczenie twoich warunków. Tak:

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

Oto kolejny przykład, który może być jeszcze bardziej przekonujące:

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

Ujemne numery wymagają nawiasach okrągłych ramach DOT-list.

Obecnie istnieje tylko YAP i XSB, które nadal oferują infix . domyślnie – i they do it differently. XSB nawet nie rozpoznaje powyższej składni kropki: potrzebujesz okrągłych nawiasów wokół niektórych nieujemnych liczb.

Napisałeś, że N.H.L wydaje się być wygodniejszym sposobem na powiedzenie [N|[H|L]]. Istnieje prosta zasada, która upraszcza takie wyrażenia w ISO Prolog: Gdy zobaczysz na liście tokeny | i [ bezpośrednio po sobie, możesz je zastąpić przez , (i usunąć odpowiednią ] po prawej stronie) . Teraz możesz napisać: [N,H|L], który nie wygląda na , który jest zły pod względem.

Możesz użyć tej reguły również w innym kierunku. Jeśli mamy listę [1,2,3,4,5], możemy użyć | jako "żyletki" takiej jak: [1,2,3|[4,5]].


Kolejna uwaga, skoro czytasz papier Naish za: W międzyczasie, to well understood że tylko call/N jest potrzebna! I ISO Prolog obsługuje call/1, call/2 do call/8.

+4

Wow, co za dokładna odpowiedź, wielkie dzięki! '[N, H | L]' jest rzeczywiście o wiele ładniejszy, nie miałem pojęcia, że ​​to było ważne. Doceniam również wskazówkę do tej wymiany, która jest naprawdę interesująca. –

+4

Możesz być zainteresowany, aby zobaczyć [jak lambdy pasują do 'call/N'] (http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord). – false

+3

Właśnie sprawdziłem i kropkowana para pojawia się w pierwszym artykule Mccarthy'ego na lisp - http://www.cs.unm.edu/~luger/cs451/resources/recursive.pdf (sekcja 3) –

9

Ta składnia pochodzi od NU-Prolog. Zobacz here. To chyba tylko normalny lista funktor/2 nowo jako operator Infix, bez konieczności tylnego pustej listy „”:

?- 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) 
+4

Składnia jest znacznie starsza niż NU (1987) lub MU. – false

+0

@false: sprawia, że ​​jestem ciekawa. Czy możesz wskazać jakieś referencje, które są łatwo dostępne? Nigdy nie widziałem, żeby był używany jako operator infuzji w innym miejscu. Nie pamiętam, że widziałem to na przykład w C & M. – twinterer

+0

Dodałem najbardziej znaczące odniesienie do mojej odpowiedzi. – false

10

Tak, masz rację, kropka to ich lista cons operatora infix . Jest to wymagane przez standard ISO Prolog, ale zwykle ukryte. Znalazłem (i użyłem) tej składni jakiś czas temu:

:- 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 */ 

Odradzono mi to. Skutecznie, składnia [A | B] to ewolucja. operator, wprowadzony dla czytelności.

OT: co to za kod?

powyższy kod to moja próba osłodzenia Prologa funkcjami. Mianowicie, wprowadza na żądanie, za pomocą $, zmienne tymczasowe wymagane (na przykład) przez wyrażeń arytmetycznych

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

każdy $ wprowadzenia zmiennej. Po ekspansji, musimy bardziej tradycyjny Fakt/2

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

Gdzie mamy wiele wyrażeń, które mogłyby być przydatne ...

+0

Dziękuję bardzo za odpowiedź! Nie rozumiem, jak działa '$', ale jest to bardzo ważne w przykładzie z '$ fact' - będę musiał poświęcić trochę czasu na poznanie tego kodu. –

+0

Aby przetestować ten kod, twój Prolog musi dostarczyć goal_expansion/2 i modules. Oba są de facto rozszerzeniami, nie zatwierdzonymi przez ISO. Przepraszam za to. W efekcie, ISO Prolog to bardzo ograniczony język WRT dostępnych implementacji, jest to jeden z głównych problemów Prologu ... – CapelliC

+2

@chac: systemy wciąż zmieniają swoje znaczenie 'goal_expansion/2' i tym podobne w wersjach od wydania do wydania podstawa. Jest to praktycznie niemożliwe do standaryzacji. – false