Warum beinhalten Sprachen keine Implikation als logischen Operator?

60

Es mag eine seltsame Frage sein, aber warum gibt es in vielen Sprachen keine Implikation als logischer Operator (Java, C, C ++, Python Haskell - obwohl es als letztes trivial ist, benutzerdefinierte Operatoren hinzuzufügen)? Ich finde logische Implikationen viel klarer zu schreiben (insbesondere in Behauptungen oder assert-ähnlichen Ausdrücken) als Negation mit oder:

encrypt(buf, key, mode, iv = null) {
    assert (mode != ECB --> iv != null);
    assert (mode == ECB || iv != null);
    assert (implies(mode != ECB, iv != null)); // User-defined function
}
Maciej Piechotka
quelle
28
Weil es nicht in C gestellt wurde; Wenn es gesetzt worden wäre, hätten es C ++, Java und C # gehabt.
m3th0dman
4
Aber C hat es nicht, weil es kein allgemeiner Bestandteil der Assemblersprache ist. Während wie alle Befehlssätze Ich kenne umfassen und, oder und nicht, ich weiß von nichts , die sind schon sagt - kein Zweifel jemand zusammen sein wird , mich von einigen obskuren Befehlssatz zu sagen , dass in Kürze tut ...
Jack Aidley
4
Vielleicht wurde es als redundant angesehen, weil (1) es weniger primitiv ist als "^", "v", "~", (2) es spart sehr wenig Tipparbeit, da "A => B" gleichbedeutend mit "~ A v B" ist. .
Giorgio
4
Sprachen, die sich mit logischen Konstruktionen befassen, haben sie eher. Unter diesen ist vor allem prolog
9
Ich bin überrascht, dass Sie denken, assertNummer 1 ist klarer als Nummer 2. Ich habe einige Zeit auf # 1 gestarrt und kann immer noch nicht erkennen, wie das Verhalten als intuitiv angesehen werden kann. (vor allem mit dem zusätzlichen !=Spiegeln der Logik)
Chris Burt-Brown

Antworten:

61

Es könnte nützlich sein, manchmal zweifellos zu haben. Gegen einen solchen Betreiber sprechen mehrere Punkte:

  • Die Charaktere -und >sind wertvoll, sowohl isoliert als auch kombiniert. Viele Sprachen benutzen sie bereits, um andere Dinge zu bedeuten. (Und viele können Unicode-Zeichensätze nicht für ihre Syntax verwenden.)
  • Implikation ist selbst für logisch denkende Personen wie Programmierer sehr kontraintuitiv. Die Tatsache, dass drei von vier Einträgen in der Wahrheitstabelle sind, trueüberrascht viele Menschen.
  • Alle anderen logischen Operatoren sind symmetrisch, was ->eine Ausnahme von der Orthogonalität darstellen würde.
  • Gleichzeitig gibt es eine einfache Problemumgehung: Verwenden Sie die Operatoren !und ||.
  • Implikation wird weitaus seltener als logisch and/ verwendet or.

Dies ist wahrscheinlich der Grund, warum der Betreiber heute selten ist. Dies könnte sicherlich häufiger vorkommen, da neue dynamische Sprachen Unicode für alles verwenden und das Überladen von Operatoren wieder in Mode kommt.

Kilian Foth
quelle
22
Ihr erster Punkt spricht nur gegen die Verwendung von '->' als Symbol für den Operator, nicht dagegen, den Operator tatsächlich zu haben. Die anderen sind gute Punkte.
AShelly
14
"Gleichzeitig gibt es eine einfache Problemumgehung: use! Und &&.": Tatsächlich besteht die einfachste Methode zum Simulieren von "->" (oder "=>", wie es in der Mathematik üblicher ist) in der Verwendung !und ||nicht , !und &&: A -> Bist äquivalent zu !A || Bdenen äquivalent zu !(A && !B).
Giorgio
22
"Die Tatsache, dass drei der vier Einträge in der Wahrheitstabelle wahr sind, überrascht viele Menschen." Wat. Ich kenne einen anderen Operator mit der gleichen Funktion, die ziemlich oft verwendet wird ...
10b0
9
@ l0b0, ich bin ein Programmierer, der CS studiert hat, aber es ist lange her. Ich hatte vergessen, dass "impliziert" eine formale Operation mit zwei Operanden ist, die einen Wahrheitswert zurückgibt, daher war ich über die Art dieser Frage zunächst verwirrt. In der Alltagssprache verwende ich "impliziert" immer dann, wenn der erste Operand bereits als wahr bekannt ist ("X ist wahr, also muss Y wahr sein"). Nach einer Minute erinnerte ich mich daran, wie formal "impliziert", aber die Tatsache bleibt bestehen - selbst für jemanden, der einmal formale Logik studiert hatte, war mir die Absicht nicht klar. Und wenn ich es nie studiert hätte, hätte es nicht einmal irgendwann Sinn ergeben.
Ben Lee
5
(a) In C -> wird als Operator verwendet. Niemand beschwert sich darüber. Ich würde => trotzdem verwenden. (b) Gegenintuitiv für wen? Die Definition von Implikation ist genau das, eine Definition. (c) Subtraktion ist nicht kommutativ. Niemand beschwert sich darüber. (d) Ich denke du meinst! und ||. Aus Präzedenzgründen werden (und) oft auch benötigt. Das gleiche Argument könnte gegen && oder ||; Treffen Sie Ihre Wahl. (e) Vielleicht liegt das daran, dass es nicht in den meisten Sprachen verfügbar ist. Viele Verwendungen von || könnte prägnant und (zumindest für mich) intuitiv durch Implikation ersetzt werden.
Theodore Norvell
54

Ich glaube, die Antwort liegt in den mathematischen Grundlagen . Implikation wird normalerweise als abgeleitete, nicht elementare Operation von Booleschen Algebren betrachtet und definiert. Programmiersprachen folgen dieser Konvention.

Dies ist Proposition I von Kapitel II aus George Booles Eine Untersuchung der Gesetze des Denkens (1854) :

Alle Operationen der Sprache als Argumentationsinstrument können von einem Zeichensystem durchgeführt werden, das sich aus folgenden Elementen zusammensetzt:

1. Buchstabensymbole wie x, y usw., die Dinge als Subjekte unserer Vorstellungen darstellen.

2nd. Operationszeichen, als +, -, ×, stehen für jene Operationen des Geistes, durch die die Vorstellungen von Dingen kombiniert oder aufgelöst werden, um neue Vorstellungen zu bilden, die dieselben Elemente beinhalten.

3rd. Das Zeichen der Identität, =.

Und diese Symbole der Logik unterliegen in ihrer Verwendung bestimmten Gesetzen, die teilweise mit den Gesetzen der entsprechenden Symbole in der Wissenschaft der Algebra übereinstimmen und sich teilweise von diesen unterscheiden.

Booles Zeichen + repräsentiert die gleiche "Operation des Geistes", die wir heute sowohl als boolesches "oder" als auch als Vereinigung von Mengen erkennen. In ähnlicher Weise entsprechen die Zeichen - und × unserer Booleschen Negation, der Ergänzung einer Menge, der Booleschen ´und´ und der Schnittmenge von Mengen.

KOMME AUS
quelle
+1 - solide Antwort. Boolesche Algebra und die Vereinfachungen in der Logik, die es ermöglicht, treiben eine Menge Programmiermethoden an. Die Verwendung eines "impliziert ..." würde möglicherweise die Bedingungen "egal" beeinträchtigen.
3
1. Das hängt von der Definition ab. Es ist möglich, zu definieren oder als a || b = !(!a && !b)(ich traf oder als abgeleiteter Operator in der Logik). 2. Der Grund, warum dies getan wird, ist in der Regel die Vereinfachung der Einführung, wie ich glaube (wir wissen, dass abgeleitete Operatoren nur Abkürzungen sind, sodass wir keinen separaten Fall für sie benötigen). @ GlenH7: Welche "egal" Bedingungen? a --> bist das gleiche wie !a || b.
Maciej Piechotka
3
Auch - wir haben andere abgeleitete Operatoren wie xor ( !=) nxor ( ==) ...
Maciej Piechotka
5
Tatsächlich können Sie alles entweder von NAND !(a && b)oder NOR ableiten !(a || b). Zum Beispiel NOT a == a NAND a, a AND b == NOT(a NAND b), a OR b == (NOT a) NAND (NOT b). Wenn Sie jedoch nur einen NAND-Operator angeben, werden Sie in das Reich der esoterischen Sprachen versetzt (was angesichts des Benutzernamens des Antwortenden überraschend gut passt ;-)).
Stefan Majewsky
1
@ Stefan: Sie können auch alles von einem IMPL ableiten.
Mason Wheeler
37

UPDATE: Diese Frage war Gegenstand meines Blogs im November 2015 . Danke für die interessante Frage!


Visual Basic 6 (und VBScript) hatte Impund EqvOperatoren. Niemand hat sie benutzt. Beide wurden in VB.NET entfernt. meines wissens hat sich niemand beschwert.

Ich arbeitete ein ganzes Jahr lang im Visual Basic-Compiler-Team (als Praktikant) und habe nie bemerkt, dass VB diese Operatoren überhaupt hatte. Wäre ich nicht der Typ gewesen, der den VBScript-Compiler geschrieben hat, und hätte daher deren Implementierungen testen müssen, hätte ich sie wahrscheinlich nicht bemerkt. Wenn der Typ im Compilerteam nichts über die Funktion weiß und sie nicht verwendet, können Sie sich über die Beliebtheit und den Nutzen der Funktion informieren.

Sie haben C-ähnliche Sprachen erwähnt. Ich kann nicht mit C oder C ++ oder Java sprechen, aber ich kann mit C # sprechen. Es gibt eine Liste der vom Benutzer vorgeschlagenen Funktionen für C #, die buchstäblich länger sind als Ihr Arm. Meines Wissens hat noch kein Benutzer dem C # -Team einen solchen Operator vorgeschlagen, und ich habe diese Liste viele Male durchgesehen.

Es ist unwahrscheinlich, dass Features, die in einer Sprache vorhanden und nicht verwendet werden und in einer anderen Sprache nicht angefordert werden, in moderne Programmiersprachen übergehen. Vor allem, wenn im Budget nicht genügend Zeit, Mühe und Geld zur Verfügung stehen, um Funktionen zu erstellen, die die Leute wirklich wollen.

Eric Lippert
quelle
IMP geht als Betreiber auf GWBASIC-Tage zurück. Ich erinnere mich daran aus dem Jahr 1979.
zarchasmpgmr
1
Ich habe gelesen, dass IMPL für Code-Verträge sehr hilfreich ist. (Was VB nicht hatte.)
Mason Wheeler
3
VBScript-Programmierer waren wahrscheinlich die Gruppe mit der geringsten Wahrscheinlichkeit, einen solchen Operator zu verwenden. Ich wünsche mir gerade, dass PowerShell einen impliziten Operator hat, damit ich einige [switch]Filterparameter einfacher und leserlicher implementieren kann.
Brianary
Ich erinnere mich an IMP von DEC BASIC. Ich erinnere mich nicht EQV. Der Operator, den ich mir oft gewünscht habe, ist "und nicht", wodurch der Operator für die rechte Hand gefördert wird, bevor er negiert wird. Somit 0xABCD12345678ul ~& 0x00200000uergäbe 0xABCD12145678ul statt 0x12145678ul.
Supercat
19

Ich kann nur raten, aber ein Grund könnte sein, dass es Workarounds gibt, die recht einfach und lesbar sind. Betrachten wir Ihr Beispiel:

if (mode != ECB) assert (iv != null);

assert (mode != ECB --> iv != null);  // <-- that's only one character shorter

Wenn Sie einen Ausdruck benötigen, kann der Inline-If-Operator verwendet werden, der in den meisten Sprachen verfügbar ist (häufig als ternärer Operator bezeichnet). Zugegeben, dies ist nicht so elegant wie A --> B, aber die Anzahl der Anwendungsfälle rechtfertigt möglicherweise nicht das Hinzufügen (und Pflegen!) Eines weiteren Operators:

assert (mode != ECB ? iv != null : true);
Heinzi
quelle
2
Wie behauptet - es gibt guten Grund. Zuerst wird (in vielen Implementierungen) die Meldung "Assertionsfehler: iv! = Null" ausgegeben, während beim zweiten Mal "Assertionsfehler: mode! = ECB -> iv! = Null" ausgegeben wird.
Maciej Piechotka
2
+1, ich wollte das Gleiche bei der Frage fragen (da ich mit "Implikation" nicht sehr vertraut bin, kommt es von Tag zu Tag nie vor). Die ifAussage ist für fast jeden viel, viel klarer.
Izkata
12

Eiffel hat Auswirkungen

Es hat eigentlich noch mehr. Es hat eine Reihe von semi-strengen Operatoren sowie streng.

Der Grund, warum Programmierer solche Dinge nicht benutzen, ist, dass sie nie genau wissen, was sie sind, wie man sie benutzt und wann man sie benutzt - und wie man mit ihnen gestaltet. Da sie nie geschult werden, fragen sie die Compiler-Autoren nie danach, weshalb sich die Compiler-Leute nicht die Mühe machen, solche Mechanismen in den Compiler einzubauen. Wenn Informatikstudenten und Schattenbaumprogrammierer eine rundere Ausbildung erhalten, werden die Compiler aufholen.

Es stellt sich heraus, dass Sie, wenn Sie eine Sprache mit solchen Booleschen Operatoren haben und wissen, wie Sie mit ihnen entwerfen und sie verwenden, diese verwenden.

In Eiffel ist die Verwendung des Schlüsselworts "implies" aufgrund von Design-by-Contract aufgrund des Booleschen Charakters von Vertragsbehauptungen eher verbreitet. Es gibt einige Verträge, die nur mit dem Operator "impliziert" ordnungsgemäß und effizient geschrieben werden können. Dies wirft dann die Bemerkung auf, dass Sprachen ohne Verträge weiterhin ohne Grund sind, die Verwendung von Implikationen zu betrachten, zu trainieren und zu implementieren.

Hinzu kommt, dass die meisten Programmierer "mathematisch-logisch-schwach" sind und uns den Rest der Geschichte erzählen. Selbst wenn Sie in Ihrer Ausbildung sehr mathematisch und logisch sind, neigen Sie dazu, solche Dinge für unnötig oder nicht nützlich zu halten, wenn Sie eine Sprache wählen, die keine Konstrukte wie Implikation implementiert. Man hinterfragt selten die Sprache und gerät in eine Echokammer von: "Nun, die Compiler-Leute sehen die Notwendigkeit nicht" und "Nun, die Programmierer sehen die Notwendigkeit nicht" - endloser und teuflischer Kreislauf.

Stattdessen müssen die Compiler-Leute auf die Theorie zurückgreifen und eine Sprachnotation schreiben, die von der Theorie vorgeschlagen oder impliziert wird (z. B. objektorientierte Theorie), unabhängig davon, was die ungewaschenen Massen von Programmierern denken oder verlangen. Von dort aus müssen Professoren, Lehrer und andere Fachkräfte junge Mush-Minds auf der Basis von Roh-Theorie und NICHT "Theorie durch die Sprachlinse" fachmännisch ausbilden. Wenn dies geschieht, werden die Menschen plötzlich aufwachen und erkennen, was ihnen gefehlt hat und was ihnen aufgezwungen wurde.

Momentan gibt es so viele Theorien, die sich als objektorientiert ausgeben, aber nur als OO-through-a-Glass-Darkly-of- [Wählen Sie Ihre Sprache]. Man kann die meisten "Theorie" -Bücher über OO nicht lesen, weil sie das, was die Theorie ist, durch die Linse einer Sprache interpretieren wollen. Völlig falsch und falsch. Es wäre, als würde man Mathe auf der Grundlage meines Taschenrechners oder meines Rechenschiebers unterrichten. NEIN - man lässt sich von der Realität etwas über sich selbst beibringen und beschreibt dann anhand einer Notation, was man beobachtet - das nennt man "Wissenschaft". Dieser andere Brei namens OO-based-on-language-X ist so verzerrt, dass er kaum die Realität darstellt.

Also, entfernen Sie sich von der Sprache, werfen Sie einen Blick auf die rohe Theorie und beginnen Sie von vorne. Lassen Sie sich nicht von Einschränkungen, Einschränkungen und Malereien einer Sprache erzählen, was die Theorie ist. Lassen Sie einfach die Realität der Theorie ihre eigene Notation diktieren und gehen Sie dann von dort zur Formulierung einer Sprache über.

Von dort werden Sie anfangen zu verstehen, wie Implikation und "Implikationen" nicht nur nützlich, sondern auch elegant und sehr cool sind!

Habe einen schönen!

Larry
quelle
7

Python hat einen versteckten Implikationsoperator.

Der Operator less-than-or-equals ist überladen, um boolesche Werte zu akzeptieren. Infolgedessen kann man es als Implikationsoperator verwenden.

Beweis durch Beispiel (Python-Code):

print (False <= False) # This will print True.
print (False <= True)  # This will print True.
print (True <= False)  # This will print False.
print (True <= True)   # This will print True.

Erinnern Sie sich an die Wahrheitstabelle des Implikationsoperators:

LEFT RIGHT RESULT
F    F     T
F    T     T
T    F     F
T    T     T
Mackenzie
quelle
2
Das ist großartig, hat aber leider die falschen Strengeigenschaften: Sollte f() implies g()nicht auswerten, g()wenn f()ist False, aber <=wird g()in diesem Fall ausgewertet .
Jon Purdy
2
@ Jon Purdy - Streng genommen ist die Kurzschlussauswertung ein optionales Merkmal von Binäroperatoren. Technisch gesehen ist dies eine absolut legitime Implementierung des Implikationsoperators. Abgesehen davon bezweifle ich wirklich, dass Guido van Rossum dies sogar als Implikationsoperator gedacht hat. Dies ist nur eine Eigenheit des Vergleichs von Booleschen Werten.
Mackenzie
Klar, ich sagte, es ist eine interessante Beobachtung, aber nicht etwas, das Sie in echten Programmen verwenden sollten, weil es nicht kurzschließt und das jemanden überraschen könnte, wenn er erwartet did_all_possible_stuff = x.do_required_stuff() and (x.supports_optional_stuff() <= x.do_optional_stuff()), dass es funktioniert.
Jon Purdy
2
Dies funktioniert auch in C und C ++.
Ben Voigt
5

Eiffel hat einen "impliziten" Operator und eignet sich sehr gut zum Schreiben von Vor- und Nachbedingungen. Es macht Code lesbarer, leider war das nie eine grundlegende Bedeutung für C-ähnliche Sprache und zu wenige Leute verwendeten Eiffel, so dass die Schönheit von "impliziert" als Operator nicht gut bekannt ist.

Lothar
quelle
2

Für mich kommt das große Problem mit impliziert, wenn die Anfangsbedingung falsch ist; Zum Beispiel: "Wenn die Sonne grün ist, dann bin ich eine Fruchtfledermaus." Wahr!

In der formalen Logik funktioniert es einfach, dem Wert "True" zuzuweisen, wenn die Bedingung der Implikation nicht erfüllt ist. Bei der Programmierung könnte dies jedoch zu kontraintuitiven und überraschenden Ergebnissen führen.

Ich denke tatsächlich, das Beispiel @Heinzi gibt oben:

if (sun.color() == "green") then assert(me.species() == "fruitbat")

Ist viel einfacher zu verstehen und weniger anfällig für Fehler aufgrund von Missverständnissen der Logik.

Im Rahmen des Testens würde ich einfach anhalten, sobald meine Annahmen falsch wurden:

assert(sun.color() == "green")
assert(me.species() == "fruitbat")

Um es mit @Eric Lippert zu sagen, als Programmierer weiß ich nicht, wann ich einen impliziten Operator verwenden würde. Das Verhalten "Falsch ist Wahr" erscheint im Kontext der mathematischen, formalen Logik nützlich, könnte jedoch zu unerwarteten Ergebnissen in der Programmlogik führen.

...

Niemand hat das gemeinsame "?" Operator, wobei "A? B: true" dasselbe ist wie "impliziert". Aber während die formale Logik der "else" -Bedingung "?" lässt den Entwickler das explizit zuweisen.

In der formalen Logik funktioniert die Verwendung von "true", aber in der Programmierung ist die bessere Antwort eher "null" oder "void" oder "skip" oder sogar falsch, wenn die Bedingung falsch ist.

Ich denke, jemand müsste den Fall stellen, warum "impliziert" ein nützlicherer Operator ist als "?" Oder "if" -Anweisungen oder einfach nur ein regulärer Programmfluss.

rauben
quelle