Kürzlich stieß ich auf ein Problem, bei dem ich den logischen Operator "OR" programmgesteuert definieren musste, ohne den Operator selbst zu verwenden.
Was ich mir ausgedacht habe, ist Folgendes:
OR(arg1, arg2)
if arg1 = True and arg2 = True
return True
else if arg1 = True and arg2 = False
return True
else if arg1 = False and arg2 = True
return True
else:
return False
Ist diese Logik richtig oder habe ich etwas verpasst?
programming-logic
logicNoob
quelle
quelle
return arg1 ? arg1 : arg2;
or
Operator neu definieren mussten .Antworten:
Ich würde sagen, das ist richtig, aber könnten Sie es nicht auf so etwas reduzieren?
Da Sie eine oder einen Vergleich durchführen, glaube ich nicht, dass Sie die Kombination wirklich überprüfen müssen. Es ist nur wichtig, ob einer von ihnen wahr ist, um wahr zurückzukehren. Andernfalls möchten wir false zurückgeben.
Wenn Sie nach einer kürzeren Version suchen, die weniger ausführlich ist, funktioniert dies auch:
quelle
if arg2 == true
).or(a, b): a ? a : b
Hier ist eine Lösung ohne oder und nicht ohne Vergleiche und boolesche Literale:
Fundamentaler geht es wohl nicht;)
quelle
true
oder vergleichtfalse
.||
gesagt, JavaScript- Operator (bei Implementierung in einer dynamisch typisierten Sprache).Eine Codezeile:
Keine Verzweigung, kein ODER.
In einer C-basierten Sprache wäre es:
Dies ist einfach eine Anwendung von De Morgans Gesetzen :
(A || B) == !(!A && !B)
quelle
if/else
Konstrukt das gleiche ist wie die Verwendung von OR, nur mit einem anderen Namen.if
entspricht der Gleichheit. Normalerweise wird in Maschinencode eineif
als Arithmetik implementiert, gefolgt von einem Vergleich mit einem Sprung auf Null.and
Kurzschlüsse kurzschließt und so für Konsistenz unter den Betreibern sorgt.if (a) return true; else if (b) return true;
scheint mehr oder weniger moralisch gleichwertig zu seinif (a OR b) return true;
, aber diese Ansicht kann durchaus bestritten werden.Wenn Sie nur
and
und habennot
, können Sie das DeMorgan-Gesetz zum Umblättern verwendenand
:... oder (noch einfacher)
...
Und da wir alle offensichtlich darauf fixiert sind, etwas zu optimieren, das sowieso fast immer als Maschinenanweisung verfügbar ist, läuft das auf Folgendes hinaus:
usw. usw. usw. usw.
Da die meisten Sprachen ein Bedingungs- und liefern, impliziert der Operator "und" ohnehin eine Verzweigung.
...
Wenn alles, was Sie haben, ist
nand
(siehe Wikipedia ):return nand (nand (arg1, arg1), nand (arg2, arg2))
quelle
return not (not arg1 and not arg2)
nand
Lösung.Funktionen (ECMAScript)
Sie benötigen lediglich Funktionsdefinitionen und Funktionsaufrufe. Sie benötigen keine Verzweigungen, Bedingungen, Operatoren oder eingebauten Funktionen. Ich werde eine Implementierung mit ECMAScript demonstrieren.
Definieren wir zunächst zwei Funktionen namens
true
undfalse
. Wir können sie so definieren, wie wir wollen, sie sind völlig willkürlich, aber wir werden sie auf eine ganz besondere Art definieren, die einige Vorteile hat, wie wir später sehen werden:tru
ist eine Funktion mit zwei Parametern, die das zweite Argument einfach ignoriert und das erste zurückgibt.fls
ist auch eine Funktion mit zwei Parametern, die das erste Argument einfach ignoriert und das zweite zurückgibt.Warum haben wir
tru
und auffls
diese Weise codiert ? Nun, auf diese Weise, die beiden Funktionen nicht nur repräsentieren die beiden Begriffetrue
undfalse
, nein, zugleich, sie auch das Konzept der „Wahl“, mit anderen Worten darstellen, sind sie auch einif
/then
/else
Ausdruck! Wir werten dieif
Bedingung aus und übergeben sie als Argumente an denthen
Block und denelse
Block. Wenn die Bedingung den Wert "0" ergibttru
, wird derthen
Block zurückgegeben. Wenn die Bedingung den Wert "0" ergibtfls
, wird derelse
Block zurückgegeben. Hier ist ein Beispiel:Dies kehrt zurück
23
und dies:kehrt zurück
42
, so wie Sie es erwarten würden.Es gibt jedoch eine Falte:
Dies druckt sowohl
then branch
als auchelse branch
! Warum?Nun, es gibt den Rückgabewert des ersten Arguments zurück, wertet jedoch beide Argumente aus, da ECMAScript streng ist und immer alle Argumente für eine Funktion auswertet, bevor die Funktion aufgerufen wird. IOW: Es wertet das erste Argument aus
console.log("then branch")
, das einfach zurückgibtundefined
und den Nebeneffekt des Druckensthen branch
auf die Konsole hat, und es wertet das zweite Argument aus, das ebenfallsundefined
als Nebeneffekt zurückgibt und auf die Konsole druckt. Dann wird der erste zurückgegebenundefined
.In λ-Kalkül, wo diese Kodierung erfunden wurde, ist das kein Problem: λ-Kalkül ist rein , was bedeutet, dass es keine Nebenwirkungen hat; daher würde man nie bemerken, dass das zweite Argument auch ausgewertet wird. Außerdem ist λ-Kalkül faul (oder zumindest wird es oft in normaler Reihenfolge ausgewertet), was bedeutet, dass es keine Argumente auswertet, die nicht benötigt werden. Also, IOW: In der λ-Rechnung würde das zweite Argument niemals ausgewertet, und wenn es so wäre, würden wir es nicht bemerken.
ECMAScript ist jedoch streng , dh es wertet immer alle Argumente aus. Nun, eigentlich nicht immer: der
if
/then
/else
zum Beispiel wertet nur denthen
Zweig , wenn die Bedingung isttrue
und wertet nur denelse
Zweig , wenn die Bedingung istfalse
. Und dieses Verhalten wollen wir mit unserem repliziereniff
. Glücklicherweise kann ECMAScript, obwohl es nicht faul ist, die Auswertung eines Codeteils verzögern, so wie es fast jede andere Sprache tut: Es wird in eine Funktion eingebunden, und wenn Sie diese Funktion nie aufrufen, wird der Code dies tun nie hingerichtet werden.Wir binden also beide Blöcke in eine Funktion ein und rufen am Ende die zurückgegebene Funktion auf:
druckt
then branch
unddruckt
else branch
.Wir konnten die traditionelle implementieren
if
/then
/ aufelse
diese Weise:Auch hier benötigen wir einen zusätzlichen Funktionsumbruch beim Aufrufen der
iff
Funktion und der zusätzlichen Funktionsaufrufklammern in der Definition voniff
, und zwar aus dem gleichen Grund wie oben:Nachdem wir diese beiden Definitionen haben, können wir sie implementieren
or
. Zunächst untersuchen wir die Wahrheitstabelle nachor
: Wenn der erste Operand wahr ist, ist das Ergebnis des Ausdrucks dasselbe wie der erste Operand. Ansonsten ist das Ergebnis des Ausdrucks das Ergebnis des zweiten Operanden. Kurz gesagt: Wenn der erste Operand isttrue
, geben wir den ersten Operanden zurück, andernfalls geben wir den zweiten Operanden zurück:Lassen Sie uns herausfinden, dass es funktioniert:
Groß! Diese Definition sieht jedoch etwas hässlich aus. Denken Sie daran,
tru
undfls
handeln Sie bereits wie eine Bedingung für sich, so dass wirklich keine Notwendigkeit bestehtiff
, und daher all diese Funktionen überhaupt zu umschließen:Da haben Sie es:
or
(plus andere boolesche Operatoren) definiert mit nichts als Funktionsdefinitionen und Funktionsaufrufen in nur wenigen Zeilen:Leider ist diese Implementierung ziemlich nutzlos: Es gibt keine Funktionen oder Operatoren in ECMAScript, die zurückgeben
tru
oderfls
alle zurückgebentrue
oderfalse
, daher können wir sie nicht mit unseren Funktionen verwenden. Aber wir können noch viel tun. Dies ist beispielsweise eine Implementierung einer einfach verknüpften Liste:Gegenstände (Scala)
Sie haben vielleicht bemerkt etwas Besonderes:
tru
undfls
eine doppelte Rolle spielen, wirken sie sowohl als die Datenwertetrue
undfalse
, aber zur gleichen Zeit, sie auch als bedingter Ausdruck handeln. Sie sind Daten und Verhalten , gebündelt in einem ... ähm ... "Ding" ... oder (wage ich zu sagen) Objekt !In der Tat
tru
undfls
sind Objekte. Und wenn Sie jemals Smalltalk, Self, Newspeak oder andere objektorientierte Sprachen verwendet haben, werden Sie feststellen, dass sie Boolesche Werte genauso implementieren. Ich werde eine solche Implementierung hier in Scala demonstrieren:Dies ist übrigens der Grund, warum das Refactoring "Bedingt durch Polymorphismus ersetzen" immer funktioniert: Sie können immer alle Bedingungen in Ihrem Programm durch polymorphen Nachrichtenversand ersetzen, da der polymorphe Nachrichtenversand, wie wir gerade gezeigt haben, Bedingungen durch einfaches Implementieren ersetzen kann. Sprachen wie Smalltalk, Self und Newspeak sind der Existenzbeweis dafür, weil diese Sprachen nicht einmal Bedingungen haben. (Sie haben auch keine Schleifen, BTW oder wirklich irgendeine Art von in die Sprache eingebauten Kontrollstrukturen, außer für den polymorphen Nachrichtenversand, auch bekannt als virtuelle Methodenaufrufe.)
Mustervergleich (Haskell)
Sie können auch
or
mithilfe des Mustervergleichs oder so etwas wie den Definitionen der Teilfunktionen von Haskell definieren:Natürlich ist der Mustervergleich eine Form der bedingten Ausführung, aber auch der objektorientierte Nachrichtenversand.
quelle
False ||| False = False
und_ ||| _ = True
stattdessen? :)True ||| undefined
Sie sich in Ghci zu sehen!Hier ist eine andere Möglichkeit, OR oder einen beliebigen logischen Operator auf die traditionellste Weise zu definieren: Verwenden Sie eine Wahrheitstabelle.
Dies ist natürlich in höheren Sprachen wie Javascript oder Perl ziemlich trivial, aber ich schreibe dieses Beispiel in C, um zu zeigen, dass die Technik nicht von höheren Sprachfunktionen abhängt:
Sie können dasselbe mit AND, NOR, NAND, NOT und XOR tun. Der Code ist so sauber, dass er wie eine Syntax aussieht, sodass Sie folgende Aufgaben ausführen können:
quelle
BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));
Eine andere Möglichkeit, die logischen Operatoren als ganzzahlige arithmetische Ausdrücke auszudrücken (sofern möglich). Auf diese Weise können viele Verzweigungen für einen größeren Ausdruck vieler Prädikate vermieden werden.
Sei Wahr 1 Sei Falsch 0
Wenn die Summe von beiden größer als 1 ist, ist es wahr oder falsch, zurückgegeben zu werden.
quelle
booleanExpression ? true : false
ist trivial gleichbooleanExpression
.return (arga+argb)>0
return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0);
:)arg1 ? 1 : 0;
. Das sind zuverlässige Ausdrücke, um einen Booleschen Wert in eine Zahl umzuwandeln. Es ist nur die return-Anweisung, die trivial überarbeitet werden kann.Die zwei Formen:
ODER
Haben neben dem Code golf-ähnlichen Vorteil, etwas kleiner als die anderen Vorschläge bisher zu sein, einen Zweig weniger. Es ist nicht einmal so dumm, die Anzahl der Zweige mit einem Mikro-Opt zu reduzieren, wenn wir über die Schaffung eines Grundelements nachdenken, das daher sehr häufig verwendet wird.
Die Definition von Javascript
||
ist ähnlich, was zusammen mit der losen Schreibweise bedeutet, dass der Ausdruckfalse || "abc"
den Wert"abc"
und42 || "abc"
den Wert hat42
.Wenn Sie bereits andere logische Operatoren haben, haben solche
nand(not(arg1), not(arg2))
möglicherweise den Vorteil, dass überhaupt keine Verzweigung erfolgt.quelle
Zusätzlich zu allen programmierten Lösungen, die das if-Konstrukt verwenden, ist es möglich, ein ODER-Gatter durch Kombinieren von drei NAND-Gattern zu konstruieren. Wenn Sie sehen möchten, wie es in Wikipedia gemacht wird, klicken Sie hier .
Daraus ergibt sich der Ausdruck,
die NOT und AND verwendet, gibt die gleiche Antwort wie OR. Beachten Sie, dass die Verwendung von NOT und AND nur eine unklare Möglichkeit ist, NAND auszudrücken.
quelle
Alle guten Antworten wurden bereits gegeben. Aber das wird mich nicht aufhalten.
Alternative:
Ich hoffe, niemand würde jemals solche Ansätze anwenden. Sie sind nur hier, um das Bewusstsein für Alternativen zu fördern.
Aktualisieren:
Da negative Zahlen beide oben genannten Ansätze unterbrechen können, ist hier ein weiterer schrecklicher Vorschlag:
Dies nutzt einfach DeMorgans Gesetze und Missbrauch der Tatsache , dass
*
die ähnlich ist ,&&
wenntrue
undfalse
wie behandelt werden1
und0
jeweils. (Warten Sie, Sie sagen, das ist kein Code Golf?)Hier ist eine anständige Antwort:
Aber das ist im Wesentlichen identisch mit anderen bereits gegebenen Antworten.
quelle
arg1+arg2
, -1 und 0 fürmax(arg1,arg2)
usw.Eine Möglichkeit zum Definieren
or
besteht in einer Nachschlagetabelle. Wir können dies explizit machen:Wir erstellen ein Array mit den Werten, die der Rückgabewert haben sollte, je nachdem, was
a
ist. Dann machen wir eine Suche. Befördert in C ++ - ähnlichen Sprachenbool
zu einem Wert, der als Array-Index mittrue
Sein1
undfalse
Sein verwendet werden kann0
.Wir können dies dann auf andere logische Operationen ausweiten:
Nun ist ein Nachteil von all diesen, dass es Präfixnotation erfordert.
und jetzt kannst du tippen
true *OR* false
und es funktioniert.Die obige Technik erfordert eine Sprache, die die argumentabhängige Suche und Vorlagen unterstützt. Sie könnten es wahrscheinlich in einer Sprache mit Generika und ADL tun.
Nebenbei können Sie das
*OR*
Obige erweitern, um mit Sets zu arbeiten. Erstellen Sie einfach eine freie Funktioninvoke
im gleichen Namespace wieor_tag
:und
set *OR* set
kehrt nun die Vereinigung der beiden zurück.quelle
Dieser erinnert mich an die charakteristischen Funktionen:
Dies gilt nur für Sprachen, die Boolesche Werte als (1, 0) behandeln können. Gilt nicht für Smalltalk oder Python, da Boolean eine Klasse ist. In Smalltalk gehen sie noch weiter (dies wird in Art eines Pseudocodes geschrieben):
Und die dualen Methoden existieren für und:
Die "Logik" ist also in der OP-Anweisung vollkommen gültig, obwohl sie ausführlich ist. Vorsicht, es ist nicht schlecht. Es ist perfekt, wenn Sie eine Funktion benötigen, die sich wie ein mathematischer Operator verhält, der beispielsweise auf einer Art Matrix basiert. Andere implementieren einen tatsächlichen Cube (wie eine Quine-McCluskey-Anweisung):
Und Sie werden bewerten oder [a] [b]
Also ja, jede Logik hier ist gültig (mit Ausnahme derjenigen, bei der der in der Sprache verwendete OR-Operator xDDDDDDD verwendet wird).
Aber mein Lieblingsgesetz ist das von DeMorgan:
!(!a && !b)
quelle
Schauen Sie sich die Swift-Standardbibliothek an und sehen Sie sich die Implementierung der Verknüpfungsoperationen OR und AND an, bei denen die zweiten Operanden nicht ausgewertet werden, wenn sie nicht benötigt / zugelassen werden.
quelle
Die Logik ist vollkommen richtig, kann aber vereinfacht werden:
Und vermutlich hat Ihre Sprache einen OR-Operator. Wenn dies nicht dem Sinn der Frage widerspricht, warum nicht?
quelle
if arg1 = True or arg2 = True { return true } else { return false }
Besser nochreturn arg1 = True or arg2 = True
.if condition then true else false
ist überflüssig.