2014-12-09 8 views
7

Warum ist die Argumentpräzedenz von **/2 (xfx) und (^)/2 (xfy) in Prolog nicht identisch?Geringfügige Inkonsistenz aufgrund unterschiedlicher Operatorpriorität von ** und^

Dies bewirkt, dass kleinere Unstimmigkeiten, wie die folgenden:

?- X = 1, Y is 1^-X. 
X = Y, Y = 1. 

und:

?- Y is 1 ** -1. 
Y = 1. 

aber:

?- X = 1, Y is 1 ** -X. 
ERROR: Syntax error: Operator priority clash 
ERROR: X = 1, Y is 1 * 
ERROR: ** here ** 
ERROR: * -X . 
+0

Excellent finden! (Braucht einige Zeit, um zu antworten) Haben Sie etwas Code in Prolog oder einer anderen Programmiersprache, in der Sie A^-B oder ähnliches schreiben? – false

+0

@false Ich bin heute bei der Implementierung von [XML Schema Datatypes 1.1] (https://github.com/wouterbeek/plXsd/blob/master/number/xsd_number_aux.pl#L146) darüber gestolpert. –

+0

Ok, du musst Klammern setzen. Hast du das woanders gesehen? – false

Antwort

2

Minor Punkt: Es ist (^)/2 und nicht ^/2 um anzuzeigen, dass ^ als Operator verwendet wird, und es gültige Prolog Syntax und ein Prädikat Indikatoren zu machen (7.1.6.6).

(**)/2 und (^)/2 sind beide auswertbaren functors (9), so können sie für Arithmetic Auswertung (8.7) mit (is)/2 und Arithmetic Vergleich (8,7) mit (=:=)/2, (<)/2 und dergleichen verwendet werden. Ihre Definitionen unterscheiden sich geringfügig.

(**)/2 gibt immer wieder einen Schwimmer auf die gleiche Weise wie (/)/2 immer gibt einen Schwimmer. (SWI folgt hier nicht dem Standard, es hat seine eigenen Konventionen).

?- X is 2**2. 
X = 4.0. 

?- X is 2/2. 
X = 1.0. 

(^)/2 ist hier integer Potenzierung zu ermöglichen, die jetzt viel wichtiger mit vielen Systemen hat sich beliebig große Zahlen zu unterstützen. Denken Sie an 2^2^X. Das heißt, wenn beide Argumente Ganzzahlen sind, ist das Ergebnis auch eine ganze Zahl, genauso wie (*)/2 diesen Fall behandelt.

?- X is 2^2, Y is 2*2. 
X = 4, Y = 4. 

?- X is 2.0^2, Y is 2.0*2. 
X = 4.0, Y = 4.0. 

In jenen Fällen, in denen (^)/2 einen realen Wert mit zwei Integer-Argumente geben würde (wie 2^ -1) wird eine Art Fehler erzeugt, und dann gibt es mehr Fehler sonst komplexe oder undefinierten Ergebnissen.

(^)/2 wurde für eine gewisse Zeit zur Potenzierung verwendet. Eine frühe Verwendung des Potenzierungsoperators ist in D.H.D. Warrens These von 1977 im Beispiel der symbolischen Differenzierung. (Es ist zumindest in Philippe Roussels Handbuch von 1975 nicht erwähnt). In der gesamten Dissertation und Handbuch für den 1978 Benutzer, die ~ Zeichen wird dort eingesetzt, wo man würde eine erwarten ^ wie in integers are restricted to the range -2~17 to 2~17-1 , ie. -131072 to 131071. Die Erklärung war die folgende und ist unverändert seit 1982.

:- op(300, xfy, ~). % 1977 
:- op(200, xfy, ^). % 1982 - today 

Von 1982 an, es verwendet wurde, in Quantifizierung von setof/3 und bagof/3, sondern auch als Lambda in Parsern natürlicher Sprache. Für all diese Anwendungen hatte es bereits die richtige Assoziativität und Priorität. Als auswertbarer Funktor war er in mehreren Systemen vorhanden.

Das erste System, das (^)/2 als auswertbaren Funktor verwendet, ist vermutlich C-Prolog.

zu diesem Erbe Vergleich schien die (**)/2 in Prolog relativ spät, höchstwahrscheinlich von Fortran inspiriert. Es wurde kurz vor dem ersten Entwurf des Ausschusses (CD 1992) zur Aufnahme vorgeschlagen (N80 1991-07, Paris-Papiere). Systeme stellten es auch als exp/2 zur Verfügung.

hat die gleiche Priorität wie (^)/2, hat aber keine Assoziativität, was zunächst als ungerade erscheinen könnte, da es einige Fälle gibt, in denen die Potenzierung zweimal üblich ist. Am bekanntesten ist die Gaussian function in seiner einfachsten Form

e -x

Anstelle der Konstanten e und Potenzierung, eine spezielle auswertbaren Funktors exp/1 vorgesehen. Oben wird also als exp(- X**2) geschrieben. In der Tat verwendet auch Wikipedia diese Notation. Angesichts dieses Funktors gibt es in diesem häufigen Fall keine Assoziativität.

Sollte es tatsächlich sein ein, würde ich sehr daran interessiert, es zu sehen.

Im Vergleich zu anderen Systemen scheint es recht üblich, zwei Arten der Potenzierung anzubieten. Denken Sie an Haskell, die ^ und ** hat.

Zum Schluss: Es ist kein häufiger Fall, in dem verschachtelten Schwimmer Potenzierung benötigt wird, zu sein scheint. Daher scheint eine minimale Unterstützung vorzuziehen.

+1

Danke für diese aufschlussreiche Antwort. Die Inkonsistenz, die ich in meiner Frage beschreibe, betrifft jedoch nicht die verschachtelte Float-Exponentiation. Es handelt sich um (nicht verschachtelte) Float-Exponentiation mit negiertem Exponenten (z. B. "? - Y = 2, X ist 2 ** -Y"). Irgendwelche Gedanken zu diesem Fall? –

+0

@WouterBeek: Ich dachte, ich hätte das erklärt: Wenn du '- X ** 2' so arbeiten willst wie in Mathe, dann kann '2 ** -X' ** nur funktionieren wenn die Prioritäten gleich sind und' ** 'ist richtig assoziativ. Ich sollte das wahrscheinlich deutlicher machen. – false

+0

Ich verstehe jetzt, warum '(**)/2' nicht assoziativ ist. Aber gibt es auch einen Grund, warum der Vorrang von "(-)/1" gleich ist wie der von "(**)/2" (beide 200)? Es scheint mir, dass die unäre Negation immer der Potenzierung vorausgehen sollte (unabhängig davon, ob Floats oder ganze Zahlen involviert sind). –

1

Der Grund (nicht Rechtfertigung) für die Inkonsistenz ist, dass in der ursprünglichen Norm von 1995 war nur **/2 eine arithmetische Potenzierung rator, während ^/2 nur zur Quantifizierung von Variablen in bagof/3 und setof/3 verwendet wurde. Für den letzteren Gebrauch machte es Sinn, Rechts-Assoziativität zu haben, so dass Sie schreiben könnten X^Y^foo(X,Y,Z). Warum **/2 nicht gegeben wurde xfy Assoziativität Ich weiß es nicht (es wäre zum Beispiel mit Fortran konsistent gewesen).

Die ^/2 als Exponentiation Operator wurde in einem "corrigendum" 2012 hinzugefügt, ohne die Syntax zu überarbeiten, was zu der aktuellen Inkonsistenz führt.

Aber beachten Sie, dass Sie einfach diese sich durch Hinzufügen einer Richtlinie beheben

:- op(200, xfy, **). 

Dies ist unwahrscheinlich, irgendwelche Probleme verursachen. Darüber hinaus sind in vielen modernen Prologs Operatordeklarationen nur lokal in einem Modul wirksam.

2

@false beantwortet Ihre erste Frage.

Das Beispiel Sie ist geben aufgrund der folgenden Unterschied:

?- integer(-1). 
true. 

?- X = 1, integer(-X). 
false. 

und die folgenden Präzedenzfälle:

?- current_op(X, xfx, **). 
X = 200. 

?- current_op(X, fy, -). 
X = 200. 
Verwandte Themen