Pourquoi les langues n'incluent-elles pas l'implication en tant qu'opérateur logique?

60

C'est peut-être une question étrange, mais pourquoi n'y a-t-il aucune implication en tant qu'opérateur logique dans de nombreux langages (Java, C, C ++, Python Haskell - bien que le dernier ait eu des opérateurs définis par l'utilisateur, il est trivial de l'ajouter)? Je trouve que l'implication logique est beaucoup plus claire à écrire (en particulier dans les assertions ou les expressions semblables à des assertions), puis la négation avec ou:

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
la source
28
Parce qu'il n'a pas été mis en C; si cela avait été mis, alors C ++, Java et C # l'auraient eu.
m3th0dman
4
Mais C ne l’a pas, à son tour, parce que ce n’est pas une partie courante du langage assembleur. Considérant que, comme tous les jeux d'instructions que je connais incluent et, ou pas, je n'en connais aucun qui implique - sans doute que quelqu'un sera là pour me parler d'un jeu d'instructions obscur qui ne va pas
tarder
4
Peut-être a-t-il été considéré comme redondant car (1) il est moins primitif que "^", "v", "~", (2) il enregistre très peu de frappe car "A => B" équivaut à "~ A v B" .
Giorgio
4
Les langues qui traitent de constructions logiques sont plus susceptibles de l'avoir. Parmi ceux-ci, le plus important est prolog
9
Je suis surpris que vous pensiez que le assertn ° 1 est plus clair que le n ° 2. Cela fait un certain temps que je regarde la N ° 1 et je ne vois toujours pas comment son comportement pourrait être considéré comme intuitif. (surtout avec le !=renversant la logique)
Chris Burt-Brown

Réponses:

61

Il pourrait être utile d'avoir parfois, sans aucun doute. Plusieurs points plaident contre un tel opérateur:

  • Les personnages -et >sont précieux, à la fois isolément et combinés. Beaucoup de langues les utilisent déjà pour signifier autre chose. (Et beaucoup ne peuvent pas utiliser de jeux de caractères unicode pour leur syntaxe.)
  • L’implication est très contre-intuitive, même pour des personnes logiques telles que les programmeurs. Le fait que trois des quatre entrées de la table de vérité truesurprennent beaucoup de monde.
  • Tous les autres opérateurs logiques sont symétriques, ce qui constituerait ->une exception à l'orthogonalité.
  • En même temps, il existe une solution de contournement simple: utilisez les opérateurs !et ||.
  • L'implication est beaucoup moins utilisée que logique and/ or.

C'est probablement pourquoi l'opérateur est rare aujourd'hui. Cela pourrait certainement devenir plus courant, car les nouveaux langages dynamiques utilisent Unicode pour tout et la surcharge d'opérateurs redevient à la mode.

Kilian Foth
la source
22
Votre premier point ne fait que contester l’utilisation du symbole '->' pour le symbole de l’opérateur, et non contre le fait qu’il ait réellement un opérateur. Les autres sont de bons points.
AShelly
14
"En même temps, il existe une solution de contournement simple: utilisez! Et &&.": En fait, le moyen le plus simple de simuler "->" (ou "=>", comme il est plus courant en Math), est d'utiliser !et ||, not !et &&: A -> Best équivalent à !A || Bce qui est équivalent à !(A && !B).
Giorgio
22
"Le fait que trois des quatre entrées de la table de vérité soient vraies surprend beaucoup de gens." Wat. Je connais un autre opérateur avec la même fonctionnalité qui est utilisé assez souvent ...
l0b0
9
@ l0b0, je suis un programmeur qui a étudié la CS, mais c'était il y a longtemps. J'avais oublié que "implique" est une opération formelle avec deux opérandes qui renvoie une valeur de vérité. Au début, j'étais confus quant à la nature de cette question. Dans le langage de tous les jours, je n'utilise jamais "implique" que lorsque le premier opérande est déjà connu comme étant vrai ("X est vrai, alors Y doit être vrai"). Après une minute, je me suis rappelé à quel point «implique» formel fonctionnait, mais le fait demeure - même pour quelqu'un qui a déjà étudié la logique formelle, l'intention n'était pas claire pour moi. Et si je ne l'avais jamais étudié, cela n'aurait pas eu de sens.
Ben Lee
5
(a) En C -> est utilisé comme opérateur. Personne ne s'en plaint. Je voudrais utiliser => de toute façon. (b) Contre-intuitif pour qui? La définition de l'implication n'est que cela, une définition. (c) la soustraction n'est pas commutative. Personne ne s'en plaint. (d) Je pense que tu veux dire! et || En raison de la priorité (et) sont souvent nécessaires. Le même argument pourrait être utilisé contre && ou ||; faites votre choix. e) C'est peut-être parce que ce n'est pas dans la plupart des langues. Beaucoup d'utilisations de || pourrait être concis et (du moins pour moi) intuitivement remplacé par implication.
Theodore Norvell
54

Je crois que la réponse réside dans les fondements mathématiques . L'implication est généralement considérée et définie comme une opération dérivée, et non élémentaire, des algèbres de Boole. Les langages de programmation suivent cette convention.

Voici la proposition I du chapitre II de George Boole dans Une enquête sur les lois de la pensée (1854) :

Toutes les opérations du langage, en tant qu’instrument de raisonnement, peuvent être conduites par un système de signes composé des éléments suivants, à savoir:

1er Symboles littéraux, tels que x, y, etc., représentant les choses en tant que sujets de nos conceptions.

2ème. Les signes d'opération, comme +, -, ×, désignent les opérations de l'esprit par lesquelles les conceptions des choses sont combinées ou résolues de manière à former de nouvelles conceptions impliquant les mêmes éléments.

3ème. Le signe d'identité, =.

Et ces symboles de la logique sont dans leur utilisation soumis à des lois définies, en partie conformes et en partie différentes des lois des symboles correspondants dans la science de l’algèbre.

Le signe de Boole + représente le même "fonctionnement de l'esprit" que nous reconnaissons aujourd'hui à la fois comme le "booléen" ou "l'union des ensembles". De la même manière, les signes - et × correspondent à notre négation booléenne, complément d’un ensemble, booléen ´ et´ et à l’intersection d’ensembles.

VIENS DE
la source
+1 - réponse solide. L'algèbre booléenne et les simplifications logiques qu'elle permet permettent de faire appel à de nombreuses méthodes de programmation. L'utilisation d'un "implique ..." pourrait potentiellement interférer avec les conditions "ne pas s'en soucier".
3
1. Cela dépend de la définition. Il est possible de définir ou en tant que a || b = !(!a && !b)(j'ai rencontré ou en tant qu'opérateur dérivé en logique). 2. La raison pour laquelle c'est fait, c'est généralement pour simplifier l'induction, ce qui est une preuve, à mon avis (nous savons que les opérateurs dérivés ne sont que des raccourcis, nous n'avons donc pas besoin d'avoir des arguments séparés à leur place). @ GlenH7: Quelles conditions "ne vous inquiétez pas"? a --> best le même que !a || b.
Maciej Piechotka
3
Nous avons également d'autres opérateurs dérivés tels que xor ( !=) nxor ( ==) ...
Maciej Piechotka
5
En fait, vous pouvez tout tirer de NAND !(a && b)ou NOR !(a || b). Par exemple, NOT a == a NAND a, a AND b == NOT(a NAND b), a OR b == (NOT a) NAND (NOT b). Mais fournir uniquement un opérateur NAND vous place dans le domaine des langages ésotériques (ce qui convient étonnamment bien, étant donné le nom d'utilisateur du répondeur ;-)).
Stefan Majewsky
1
@Stefan: Vous pouvez également tout tirer d'un IMPL.
Mason Wheeler
37

MISE À JOUR: Cette question a été le sujet de mon blog en novembre 2015 . Merci pour la question intéressante!


Visual Basic 6 (et VBScript) avait Impet Eqvopérateurs. Personne ne les utilisait. Les deux ont été supprimés dans VB.NET; à ma connaissance, personne ne s'est plaint.

J'ai travaillé sur l'équipe du compilateur Visual Basic (en tant que stagiaire) pendant un an et je n'ai jamais remarqué que VB avait même ces opérateurs. Si je n'avais pas été le type qui a écrit le compilateur VBScript et que j'ai donc dû tester leurs implémentations, je ne les aurais probablement pas remarqués. Si le membre de l' équipe de compilation ne connaît pas la fonctionnalité et ne l'utilise pas, cela vous dit quelque chose sur la popularité et l'utilité de la fonctionnalité.

Vous avez mentionné les langues de type C. Je ne peux pas parler en C, C ++ ou Java, mais je peux parler en C #. Il existe une liste de fonctionnalités suggérées par les utilisateurs pour C # littéralement plus longues que votre bras. À ma connaissance, aucun utilisateur n'a jamais proposé un tel opérateur à l'équipe C # et j'ai parcouru cette liste à maintes reprises.

Les fonctionnalités existantes et non utilisées dans une langue et qui ne sont jamais demandées dans une autre sont des candidats improbables à intégrer les langages de programmation modernes. En particulier , lorsqu'il n'y a pas assez de temps et d' efforts et d' argent disponible dans le budget pour faire que les gens caractéristiques font défaut.

Eric Lippert
la source
IMP revient en tant qu'opérateur aux jours GWBASIC. Je m'en souviens de 1979.
zarchasmpgmr
1
J'ai lu qu'IMPL est très utile pour les contrats de code. (Ce que VB n'avait pas.)
Mason Wheeler
3
Les programmeurs VBScript étaient probablement le groupe le moins susceptible d’utiliser un tel opérateur. Je souhaite à présent que PowerShell ait un opérateur implique afin que je puisse implémenter plus facilement et plus lisiblement certains [switch]paramètres de filtre.
brianary
Je me souviens de IMP de DEC BASIC. Je ne m'en souviens pas EQV. L'opérateur que j'ai souvent souhaité serait "et non", ce qui encouragerait l'opérateur de droite avant de le nier. Ainsi, vous 0xABCD12345678ul ~& 0x00200000uobtiendrez 0xABCD12145678ul plutôt que 0x12145678ul.
Supercat
19

Je peux seulement deviner, mais l'une des raisons pourrait être qu'il existe des solutions de contournement assez simples et lisibles. Considérons votre exemple:

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

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

Si vous avez besoin d'une expression, vous pouvez utiliser l'opérateur inline-if disponible dans la plupart des langues (souvent appelé opérateur ternaire). Certes, cela n’est pas aussi élégant que A --> B, mais le nombre de cas d’utilisation pourrait ne pas justifier l’ajout (et le maintien!) D’un autre opérateur:

assert (mode != ECB ? iv != null : true);
Heinzi
la source
2
En tant qu'affirmations - il y a une bonne raison. Le premier produira (dans beaucoup d'implémentations) le message "échec d'assertion: iv! = Null" tandis que le deuxième "échec d'assertion: mode! = ECB -> iv! = Null".
Maciej Piechotka
2
+1, j'étais sur le point de poser la même chose à propos de la question (étant donné que je ne suis pas très familier avec "l'implication", cela ne se produit jamais au jour le jour). La ifdéclaration est beaucoup, beaucoup plus claire pour à peu près tout le monde.
Izkata
12

Eiffel a des implications

Il en a encore plus. Il a un certain nombre d'opérateurs semi-stricts ainsi que stricts.

La raison pour laquelle les programmeurs n'utilisent pas de telles choses est parce qu'ils ne sont jamais formés pour savoir exactement ce qu'ils sont, comment les utiliser et quand les utiliser - ainsi que comment concevoir avec eux. Parce qu'ils ne sont jamais formés, ils ne le demandent jamais aux rédacteurs du compilateur, c'est pourquoi les compilateurs ne se donnent pas la peine d'insérer de tels mécanismes dans le compilateur. Lorsque les étudiants en informatique et les programmeurs Shade-tree commenceront à recevoir une éducation plus complète, les compilateurs commenceront à se mettre à niveau.

Il s'avère qu'une fois que vous avez un langage avec de tels opérateurs booléens et que vous savez concevoir avec eux et les utiliser, vous les utilisez.

Dans Eiffel, l’utilisation du mot-clé "implique" est assez importante en raison de la conception par contrat en raison de la nature booléenne des assertions de contrat. Certains contrats ne peuvent être écrits correctement et efficacement qu'avec l'opérateur "implique". Cela nous amène à dire que les langues sans contrat sont en outre sans raison d’examiner, de former et de mettre en œuvre l’utilisation de l’implication.

Ajoutez à cela que la plupart des programmeurs sont "faibles en maths et en logique" nous dit le reste de l'histoire. Même si vous avez beaucoup de math et de logique dans votre éducation, quand on choisit un langage qui ne met pas en œuvre des constructions telles que l'implication, on a tendance à penser que de telles choses sont inutiles ou inutiles. On met rarement en doute le langage et on entre dans une chambre d'écho de: "Les compilateurs ne voient pas la nécessité" et "Les programmeurs ne voient pas la nécessité" - cercle vicieux et sans fin.

Au lieu de cela, les compilateurs doivent sauvegarder la théorie, écrire une notation de langage suggérée ou implicite par la théorie (par exemple, la théorie orientée objet), indépendamment de ce que les masses non-lavées de pensées pensent ou demandent. À partir de là, les professeurs, enseignants et autres professionnels doivent former de manière experte de jeunes esprits fondés sur la théorie brute et non sur une "théorie à travers le prisme du langage". Lorsque cela se produit, les gens se réveillent soudainement et réalisent ce qui leur manque et ce qui leur a été imposé.

À l'heure actuelle - il y a tellement de théories qui se font passer pour des objets orientés, mais qui ne sont que de simples mots-clés. On ne peut pas lire la plupart des livres "théoriques" sur OO car ils veulent interpréter la théorie à travers le prisme d'une langue. Totalement faux et incorrect. Ce serait comme enseigner ma calculatrice basée sur les mathématiques ou ma règle de diapositive. NON - on permet à la réalité d'enseigner soi-même et on utilise ensuite une notation pour décrire ce que l'on observe - c'est ce qu'on appelle "la science". Cette autre composition appelée OO-based-on-language-X est tellement biaisée qu'elle représente à peine la réalité.

Alors, éloignez-vous de la langue, jetez un coup d'œil à la théorie brute et recommencez. Ne laissez pas les limitations, les contraintes et les travaux de peinture d’une langue vous expliquer la théorie. Laissez simplement la réalité de la théorie dicter sa propre notation, puis passez à la formulation d’un langage.

A partir de là, vous commencerez à comprendre comment l'implication et "implique" est non seulement utile, mais élégant et très cool!

Avoir un grand!

Larry
la source
7

Python a un opérateur d'implication de manière cachée.

L'opérateur inférieur à ou égal est surchargé pour accepter les valeurs booléennes. En conséquence, on peut l'utiliser comme opérateur d'implication.

Preuve par exemple (code Python):

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.

Rappelez-vous que la table de vérité de l'opérateur d'implication est:

LEFT RIGHT RESULT
F    F     T
F    T     T
T    F     F
T    T     T
Mackenzie
la source
2
Ceci est génial, mais a malheureusement les mauvaises propriétés de rigueur: f() implies g()ne devrait pas évaluer g()si f()est False, mais <=évalue g()dans ce cas.
Jon Purdy
2
@Jon Purdy - À proprement parler, l'évaluation des courts-circuits est une fonctionnalité optionnelle des opérateurs binaires. Donc techniquement, ceci est une implémentation parfaitement légitime de l'opérateur d'implication. Cela dit, je doute vraiment que Guido van Rossum ait même voulu que ce soit un opérateur d'implication. C'est juste une bizarrerie de comparer des booléens.
Mackenzie
Bien sûr, je disais que c’est une observation intéressante, mais que vous ne devriez pas l’utiliser dans de vrais programmes, car ce n’est pas un court-circuit et cela pourrait prendre quelqu'un par surprise s’ils s’attendaient did_all_possible_stuff = x.do_required_stuff() and (x.supports_optional_stuff() <= x.do_optional_stuff())à travailler.
Jon Purdy
2
Cela fonctionne également en C et C ++.
Ben Voigt
5

Eiffel a un opérateur "implique" et c'est très agréable pour écrire des pré-conditions et des post-conditions. Cela rend le code plus lisible, malheureusement cela n’a jamais été une intention fondamentale pour le langage C et trop peu de gens utilisent eiffel, donc la beauté de "implique" en tant qu’opérateur n’est pas bien connue.

Lothar
la source
2

Pour moi, le gros problème avec implique vient lorsque la condition initiale est fausse; par exemple: "Si le soleil est vert, alors je suis une batte de fruits." Vrai!

En logique formelle, il suffit d'assigner "True" à la valeur lorsque la condition de l'implication n'est pas remplie. Mais en programmation, cela pourrait conduire à des résultats contre-intuitifs et surprenants.

En fait, je pense que l'exemple donné par @Heinzi ci-dessus:

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

Est beaucoup plus facile à comprendre et moins sujet aux erreurs en raison d’une mauvaise compréhension de la logique.

Dans le contexte des tests, je m'arrêterais au moment où mes hypothèses deviendraient fausses:

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

Donc, au point de @Eric Lippert, en tant que programmeur, je ne sais pas quand j'utiliserais un opérateur implique. Le comportement "False is True" semble utile dans le contexte de la logique mathématique formelle, mais pourrait conduire à des résultats inattendus dans la logique de programme.

...

Personne n'a mentionné le commun "?" opérateur, où "A? B: true" est identique à "implique". Mais alors que la logique formelle assigne vrai à la condition "else", "?" laisse le développeur assigner cela explicitement.

En logique formelle, l’utilisation de "vrai" marche, mais en programmation, si la condition est fausse, la meilleure réponse est plutôt "nulle" ou "vide" ou "ignorer", voire même fausse.

Je pense que quelqu'un devrait expliquer pourquoi "implique" est un opérateur plus utile que "?", Ou "if", ou simplement un déroulement de programme normal.

Rob
la source