Récemment, j'ai rencontré un problème qui m'a obligé à définir l'opérateur logique "OU" par programme, mais sans utiliser l'opérateur lui-même.
Voici ce que j'ai trouvé:
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
Cette logique est-elle correcte ou ai-je oublié quelque chose?
programming-logic
logicNoob
la source
la source
return arg1 ? arg1 : arg2;
or
opérateur.Réponses:
Je dirais que c'est correct, mais ne pourriez-vous pas le condenser en quelque chose de ce genre?
Puisque vous faites une comparaison ou une comparaison, je ne pense pas que vous ayez vraiment besoin de vérifier la combinaison. Il importe simplement que l’un d’eux soit vrai pour revenir vrai. Sinon, nous voulons retourner false.
Si vous recherchez une version plus courte et moins détaillée, cela fonctionnera également:
la source
if arg2 == true
).or(a, b): a ? a : b
Voici une solution sans ou, et non, comparaisons et littéraux booléens:
Ça ne devient probablement pas plus fondamental que ça;)
la source
true
oufalse
.||
Opérateur JavaScript en un mot (lorsqu'il est implémenté dans un langage typé dynamiquement).Une ligne de code:
Pas de branchement, pas de OU.
Dans un langage basé sur C, ce serait:
Ceci est simplement une application des lois de De Morgan :
(A || B) == !(!A && !B)
la source
if/else
construction est la même chose que d’utiliser OR, juste avec un nom différent.if
équivaut à l'égalité. Normalement, dans le code machine, anif
est implémenté sous forme arithmétique suivie d'une comparaison à zéro avec un saut.and
, assurant ainsi la cohérence entre les opérateurs.if (a) return true; else if (b) return true;
semble plus ou moins moralement équivalentif (a OR b) return true;
, mais ce point de vue peut être sujet à controverse.Si vous avez seulement
and
etnot
, vous pouvez utiliser la loi de DeMorgan pour retournerand
:... ou (encore plus simplement)
...
Et comme nous avons tous apparemment tendance à vouloir optimiser quelque chose qui est presque toujours disponible en tant qu'instruction machine, cela revient à:
etc. etc. etc. etc.
Étant donné que la plupart des langues fournissent un conditionnel et, les chances sont que l'opérateur "et" implique de toute façon une branche.
...
Si tout ce que vous avez est
nand
(voir wikipedia ):renvoyer nand (nand (arg1, arg1), nand (arg2, arg2))
la source
return not (not arg1 and not arg2)
nand
solution pure .Fonctions (ECMAScript)
Vous n'avez besoin que de définitions de fonctions et d'appels de fonctions. Vous n'avez pas besoin de branches, de conditions, d'opérateurs ou de fonctions intégrées. Je vais démontrer une implémentation en utilisant ECMAScript.
Premièrement, définissons deux fonctions appelées
true
etfalse
. Nous pouvons les définir comme bon nous semble, ils sont complètement arbitraires, mais nous les définirons de manière très spéciale, ce qui présente certains avantages, comme nous le verrons plus tard:tru
est une fonction à deux paramètres qui ignore simplement son deuxième argument et renvoie le premier.fls
est également une fonction à deux paramètres qui ignore simplement son premier argument et renvoie le second.Pourquoi avons-nous encodé
tru
et defls
cette façon? Eh bien, de cette façon, les deux fonctions ne représentent pas seulement les deux concepts detrue
etfalse
, en même temps, elles représentent également le concept de "choix", en d’autres termes, elles sont aussi une expressionif
/then
/else
! Nous évaluons laif
condition et lui passons lethen
bloc et leelse
bloc comme arguments. Si la condition est évaluée àtru
, elle retournera lethen
bloc. Si elle évaluera àfls
, elle retournera leelse
bloc. Voici un exemple:Ceci retourne
23
et ceci:retourne
42
, comme on peut s'y attendre.Il y a une ride, cependant:
Cela imprime à la fois
then branch
etelse branch
! Pourquoi?Eh bien, il renvoie la valeur de retour du premier argument, mais il évalue les deux arguments, car ECMAScript est strict et évalue toujours tous les arguments d'une fonction avant d'appeler la fonction. IOW: il évalue le premier argument qui est
console.log("then branch")
, qui retourne simplementundefined
et a l’effet secondaire d’imprimerthen branch
sur la console, et le deuxième argument, qui retourne égalementundefined
et est imprimé sur la console en tant qu’effet secondaire. Ensuite, il retourne le premierundefined
.Dans le λ-calcul, où ce codage a été inventé, ce n'est pas un problème: le λ-calcul est pur , ce qui signifie qu'il n'a pas d'effets secondaires; par conséquent, vous ne remarquerez jamais que le deuxième argument est également évalué. De plus, le λ-calcul est paresseux (ou du moins, il est souvent évalué dans un ordre normal), ce qui signifie qu'il n'évalue pas les arguments inutiles. Donc, IOW: dans le λ-calcul, le deuxième argument ne serait jamais évalué, et si c'était le cas, nous ne le remarquerions pas.
ECMAScript, cependant, est strict , c’est-à-dire qu’il évalue toujours tous les arguments. En fait, pas toujours: le
if
/then
/else
, par exemple, n’évalue lathen
branche que si la condition esttrue
et n’évalue que laelse
branche si la condition estfalse
. Et nous voulons reproduire ce comportement avec notreiff
. Heureusement, même si ECMAScript n’est pas paresseux, il a le moyen de retarder l’évaluation d’un morceau de code, comme presque toutes les autres langues: encapsulez-le dans une fonction et si vous n’appelez jamais cette fonction, le code ne jamais être exécuté.Donc, nous encapsulons les deux blocs dans une fonction et, à la fin, appelons la fonction renvoyée:
estampes
then branch
etimpressions
else branch
.Nous pourrions mettre en œuvre le traditionnel
if
/then
/ deelse
cette façon:Encore une fois, nous avons besoin de fonctions supplémentaires lors de l'appel de la
iff
fonction et de l'appel de fonction supplémentaire entre parenthèses dans la définition deiff
, pour la même raison que ci-dessus:Maintenant que nous avons ces deux définitions, nous pouvons les appliquer
or
. Premièrement, nous examinons la table de vérité pouror
: si le premier opérande est la vérité, le résultat de l'expression est identique à celui du premier opérande. Sinon, le résultat de l'expression est le résultat du deuxième opérande. En bref: si le premier opérande esttrue
, nous retournons le premier opérande, sinon nous retournons le deuxième opérande:Voyons si cela fonctionne:
Génial! Cependant, cette définition est un peu moche. Rappelez-vous,
tru
etfls
agissez déjà comme un conditionnel tout seul, donc il n'y a vraiment pas besoin deiff
, et donc de toute cette fonction encapsulant du tout:Voilà ce que vous avez:
or
(plus d’autres opérateurs booléens) défini avec seulement des définitions de fonctions et des appels de fonctions en seulement quelques lignes:Malheureusement, cette implémentation est plutôt inutile: il n'y a pas de fonctions ou d'opérateurs dans ECMAScript qui retournent
tru
ou qui reviennentfls
toustrue
oufalse
, nous ne pouvons donc pas les utiliser avec nos fonctions. Mais il y a encore beaucoup à faire. Par exemple, il s’agit d’une implémentation d’une liste à lien unique:Objets (Scala)
Vous avez peut-être remarqué quelque chose de particulier:
tru
etfls
jouant un double rôle, ils agissent à la fois comme valeurs de donnéestrue
etfalse
, mais en même temps, ils agissent également comme une expression conditionnelle. Ce sont des données et des comportements , regroupés dans un… euh… «chose»… ou (oserais-je dire) objet !En effet,
tru
etfls
sont des objets. Et si vous avez déjà utilisé Smalltalk, Self, Newspeak ou d’autres langages orientés objet, vous aurez remarqué qu’ils implémentent les booléens exactement de la même manière. Je démontrerai une telle implémentation ici à Scala:C’est la raison pour laquelle le refactoring Remplacer conditionnel par polymorphisme fonctionne toujours: vous pouvez toujours remplacer n’importe quelle condition de votre programme par une distribution de messages polymorphes, car, comme nous venons de le montrer, la distribution de messages polymorphes peut remplacer des conditions en les implémentant simplement. Des langages comme Smalltalk, Self et Newspeak en sont la preuve, car ils n’ont même pas de condition. (Ils ne sont pas aussi des boucles, BTW, ou vraiment une sorte de structures de contrôle intégré langue sauf pour l' expédition des messages polymorphes appels de méthode alias virtuels.)
Correspondance de modèle (Haskell)
Vous pouvez également définir en
or
utilisant un filtrage par motif, ou quelque chose comme les définitions de fonctions partielles de Haskell:Bien entendu, la mise en correspondance de modèles est une forme d'exécution conditionnelle, mais il en va de même pour l'envoi de messages orientés objet.
la source
False ||| False = False
et à la_ ||| _ = True
place? :)True ||| undefined
vous dans ghci pour voir!Voici une autre façon de définir OR, ou même n'importe quel opérateur logique, en utilisant la méthode la plus traditionnelle: définissez une table de vérité.
Ceci est bien sûr assez simple à faire dans les langages de niveau supérieur tels que Javascript ou Perl, mais j'écris cet exemple en C pour montrer que la technique ne dépend pas des fonctionnalités de langage de haut niveau:
Vous pouvez faire la même chose avec AND, NOR, NAND, NOT et XOR. Le code est suffisamment propre pour ressembler à la syntaxe, ce qui vous permet de faire des choses comme ceci:
la source
BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));
Une autre façon d'exprimer les opérateurs logiques sous forme d'expressions arithmétiques entières (lorsque cela est possible). De cette façon, vous évitez beaucoup de ramifications pour une expression plus large de nombreux prédicats.
Let True soit 1 Let False est 0
si la somme des deux est supérieure à 1, il est alors vrai ou faux d'être renvoyé.
la source
booleanExpression ? true : false
est trivialement égal àbooleanExpression
.return (arga+argb)>0
return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0);
:)arg1 ? 1 : 0;
. Ce sont des expressions fiables pour transformer un booléen en nombre. C'est seulement la déclaration de retour qui peut être trivialement refactorisée.Les deux formes:
OU
Avoir l’avantage, au même titre que le code golf, d’être un peu plus petit que les autres suggestions faites jusqu’à présent, une branche de moins. Ce n’est même pas aussi ridicule que le micro-choix de réduire le nombre de branches si nous envisageons la création d’un primitif qui serait donc très utilisé.
La définition de Javascript
||
s'apparente à celle-ci, ce qui, combiné à sa frappe lâche, signifie que l'expressionfalse || "abc"
a la valeur"abc"
et42 || "abc"
a la valeur42
.Cependant, si vous avez déjà d'autres opérateurs logiques, ceux-ci
nand(not(arg1), not(arg2))
pourraient ne pas avoir de branche du tout.la source
En plus de toutes les solutions programmées utilisant la construction if, il est possible de construire une porte OU en combinant trois portes NAND. Si vous voulez voir comment cela fonctionne dans wikipedia, cliquez ici .
A partir de là, l'expression,
qui utilise NOT et AND donne la même réponse que OR. Notez que l’utilisation de NOT et AND n’est qu’une manière obscure d’exprimer NAND.
la source
Toutes les bonnes réponses ont déjà été données. Mais je ne laisserai pas cela m'arrêter.
Alternativement:
J'espère que personne n'utilisera jamais de telles approches. Ils ne sont là que pour promouvoir la connaissance des alternatives.
Mise à jour:
Puisque les nombres négatifs peuvent casser les deux approches ci-dessus, voici une autre suggestion affreuse:
Cela utilise simplement les lois de DeMorgan et abuse du fait que
*
c'est semblable à&&
quandtrue
etfalse
sont traités comme1
et0
respectivement. (Attendez, vous dites que ce n'est pas du code golf?)Voici une réponse décente:
Mais c'est essentiellement identique aux autres réponses déjà données.
la source
arg1+arg2
, -1 et 0 pourmax(arg1,arg2)
, etc.Une façon de définir
or
consiste à utiliser une table de correspondance. Nous pouvons rendre ceci explicite:nous créons un tableau avec les valeurs que la valeur de retour doit avoir en fonction de ce qui
a
est. Ensuite, nous faisons une recherche. En C ++, comme les langages,bool
promeut une valeur utilisable comme index de tableau, avectrue
être1
etfalse
être0
.Nous pouvons ensuite l'étendre à d'autres opérations logiques:
Maintenant, l’un des inconvénients de tout cela est qu’il nécessite une notation par préfixe.
et maintenant vous pouvez taper
true *OR* false
et ça marche.La technique ci-dessus nécessite un langage prenant en charge la recherche dépendante d'arguments et les modèles. Vous pourriez probablement le faire dans un langage avec des génériques et ADL.
En passant, vous pouvez étendre ce qui
*OR*
précède pour travailler avec des ensembles. Créez simplement une fonction libreinvoke
dans le même espace de noms queor_tag
:et
set *OR* set
retourne maintenant l'union des deux.la source
Celui-ci me rappelle les fonctions charasteristiques:
Ceci ne s'applique qu'aux langues pouvant traiter les booléens comme (1, 0). Ne s'applique pas à Smalltalk ou à Python car boolean est une classe. En smalltalk, ils vont encore plus loin (cela sera écrit dans une sorte de pseudocode):
Et les doubles méthodes existent pour et:
La "logique" est donc parfaitement valable dans la déclaration OP, même si elle est verbeuse. Attention, c'est pas mal. C'est parfait si vous avez besoin d'une fonction qui agit comme un opérateur mathématique basé sur, par exemple, une sorte de matrice. D'autres implémenteraient un cube réel (comme une instruction Quine-McCluskey):
Et vous évaluerez ou [a] [b]
Donc, oui, chaque logique ici est valide (sauf celle qui est publiée comme utilisant l'opérateur xDDDDDDDD en langage OU).
Mais mon préféré est la loi de DeMorgan:
!(!a && !b)
la source
Examinez la bibliothèque standard Swift et vérifiez son implémentation des opérations de raccourci OU et de raccourci AND, qui n'évaluent pas les seconds opérandes si elles ne sont pas nécessaires / autorisées.
la source
La logique est parfaitement correcte, mais peut être simplifiée:
Et vraisemblablement, votre langue a un opérateur OU alors - à moins que cela ne soit contraire à l'esprit de la question - pourquoi pas
la source
if arg1 = True or arg2 = True { return true } else { return false }
Mieux encorereturn arg1 = True or arg2 = True
.if condition then true else false
est redondant.