¿Por qué los idiomas no incluyen la implicación como operador lógico?

60

Puede ser una pregunta extraña, pero ¿por qué no hay implicación como operador lógico en muchos lenguajes (Java, C, C ++, Python Haskell, aunque como último tiene operadores definidos por el usuario, es trivial agregarlo)? Encuentro la implicación lógica mucho más clara de escribir (particularmente en afirmaciones o expresiones similares a afirmaciones) y luego negación con o:

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
fuente
28
Porque no fue puesto en C; si se hubiera puesto, C ++, Java y C # lo habrían tenido.
m3th0dman
44
Pero C no lo tiene, a su vez, porque no es una parte común del lenguaje ensamblador. Mientras que como todos los conjuntos de instrucciones que conozco incluyen y, o no, no conozco ninguno que incluya implicar, sin duda alguien vendrá a contarme algún conjunto de instrucciones oscuras que en breve ...
Jack Aidley
44
Tal vez se consideró redundante porque (1) es menos primitivo que "^", "v", "~", (2) ahorra muy poca escritura ya que "A => B" es equivalente a "~ A v B" .
Giorgio
44
Los lenguajes que tratan con construcciones lógicas tienen más probabilidades de tenerlo. El principal de ellos es prolog
99
Me sorprende que pienses que el n assert. ° 1 es más claro que el n. ° 2. He estado mirando al # 1 por algún tiempo y todavía no puedo ver cómo su comportamiento podría considerarse intuitivo. (especialmente con el !=giro adicional de la lógica)
Chris Burt-Brown

Respuestas:

61

Podría ser útil tener a veces, sin duda. Varios puntos argumentan en contra de dicho operador:

  • Los personajes -y >son valiosos, tanto de forma aislada como combinada. Muchos idiomas ya los usan para significar otras cosas. (Y muchos no pueden usar juegos de caracteres unicode para su sintaxis).
  • La implicación es muy contra-intuitiva, incluso para personas con mentalidad lógica como los programadores. El hecho de que tres de las cuatro entradas de la tabla de verdad sean truesorpresas para muchas personas.
  • Todos los demás operadores lógicos son simétricos, lo que haría ->una excepción a la ortogonalidad.
  • Al mismo tiempo, hay una solución fácil: usar operadores !y ||.
  • La implicación se usa con mucha menos frecuencia que la lógica and/ or.

Esta es probablemente la razón por la cual el operador es raro hoy en día. Ciertamente, podría volverse más común, ya que los nuevos lenguajes dinámicos usan Unicode para todo y la sobrecarga del operador vuelve a estar de moda.

Kilian Foth
fuente
22
Su primer punto solo argumenta en contra de usar '->' como el símbolo para el operador, no en contra de tener el operador. Los otros son buenos puntos.
AShelly
14
"Al mismo tiempo, hay una solución fácil: usar! Y &&.": De hecho, la forma más simple de simular "->" (o "=>", como es más común en matemáticas), es usar !y ||, no !y &&: A -> Bes equivalente a lo !A || Bque es equivalente a !(A && !B).
Giorgio el
22
"El hecho de que tres de las cuatro entradas de la tabla de verdad sean verdaderas sorprende a muchas personas". Wat Conozco otro operador con la misma función que se utiliza con bastante frecuencia ...
l0b0
99
@ l0b0, soy un programador que estudió CS, pero fue hace mucho tiempo. Había olvidado que "implica" es una operación formal con dos operandos que devuelve un valor de verdad, por lo que al principio estaba confundido sobre la naturaleza de esta pregunta. En el habla cotidiana, solo uso "implica" cuando ya se sabe que el primer operando es verdadero ("X es verdadero, entonces Y debe ser verdadero"). Después de un minuto, recordé cómo funcionan las "implicaciones" formales, pero el hecho es que, incluso para alguien que alguna vez estudió lógica formal, la intención no estaba clara para mí. Y si nunca lo hubiera estudiado, ni siquiera tendría sentido.
Ben Lee
55
(a) En C -> se utiliza como operador. Nadie se queja de eso. Yo usaría => de todos modos. (b) ¿Contra-intuitivo para quién? La definición de implicación es solo eso, una definición. (c) la resta no es conmutativa. Nadie se queja de eso. (d) ¡Creo que te refieres! y ||. Debido a la precedencia (y) a menudo también se necesitan. El mismo argumento podría usarse contra && o ||; elige tu opción. (e) Quizás eso se deba a que no está en la mayoría de los idiomas. Muchos usos de || podría ser concisa y (al menos para mí) intuitivamente reemplazado por implicación.
Theodore Norvell
54

Creo que la respuesta se encuentra en los fundamentos matemáticos . La implicación generalmente se considera y define como una operación derivada, no elemental, de álgebras booleanas. Los lenguajes de programación siguen esta convención.

Esta es la Proposición I del Capítulo II de Una investigación de las leyes del pensamiento de George Boole (1854) :

Todas las operaciones del lenguaje, como instrumento de razonamiento, pueden realizarse mediante un sistema de signos compuesto de los siguientes elementos, a saber:

1er. Símbolos literales, como x, y, etc., que representan cosas como sujetos de nuestras concepciones.

2do. Signos de operación, como +, -, ×, que representan aquellas operaciones de la mente mediante las cuales las concepciones de las cosas se combinan o resuelven para formar nuevas concepciones que involucran los mismos elementos.

3er. El signo de identidad, =.

Y estos símbolos de la lógica están sujetos a leyes definidas, en parte de acuerdo y en parte diferentes de las leyes de los símbolos correspondientes en la ciencia del álgebra.

El signo + de Boole representa la misma "operación de la mente" que hoy reconocemos como el "or" booleano y la unión de conjuntos. Del mismo modo, los signos - y × corresponden a nuestra negación booleana, complemento de un conjunto, "y" booleanos e intersección de conjuntos.

VIENE DE
fuente
+1: respuesta sólida. El álgebra booleana y las simplificaciones lógicas que permite manejan una gran cantidad de metodología de programación. Usar un "implica ..." podría interferir potencialmente con las condiciones de "no me importa".
3
1. Eso depende de la definición. Es posible definir o como a || b = !(!a && !b)(conocí o como operador derivado en lógica). 2. Creo que la razón por la que se hace es para simplificar las pruebas de inducción (sabemos que los operadores derivados son solo atajos, por lo que no necesitamos tener un caso separado para ellos). @ GlenH7: ¿Qué condiciones de "no me importa"? a --> bes el mismo que !a || b.
Maciej Piechotka
3
Además, tenemos otros operadores derivados como xor ( !=) nxor ( ==) ...
Maciej Piechotka
55
En realidad, puede derivar todo de NAND !(a && b)o NOR !(a || b). Por ejemplo, NOT a == a NAND a, a AND b == NOT(a NAND b), a OR b == (NOT a) NAND (NOT b). Pero proporcionar solo un operador NAND lo coloca en el ámbito de los lenguajes esotéricos (que se ajusta sorprendentemente bien, dado el nombre de usuario del respondedor ;-)).
Stefan Majewsky
1
@Stefan: También puede derivar todo de un IMPL.
Mason Wheeler
37

ACTUALIZACIÓN: Esta pregunta fue el tema de mi blog en noviembre de 2015 . Gracias por la interesante pregunta!


Visual Basic 6 (y VBScript) tenía Impy Eqvoperadores. Nadie los usó. Ambos fueron eliminados en VB.NET; Que yo sepa, nadie se quejó.

Trabajé en el equipo compilador de Visual Basic (como pasante) durante un año completo y nunca me di cuenta de que VB incluso tenía esos operadores. Si no hubiera sido el tipo que escribió el compilador VBScript y, por lo tanto, hubiera tenido que probar sus implementaciones, probablemente no me habría dado cuenta. Si el chico del equipo del compilador no conoce la función y no la usa, eso le dice algo sobre la popularidad y la utilidad de la función.

Mencionaste lenguajes tipo C. No puedo hablar con C o C ++ o Java, pero puedo hablar con C #. Hay una lista de características sugeridas por el usuario para C #, literalmente más larga que su brazo. Que yo sepa, ningún usuario ha propuesto un operador de este tipo al equipo de C #, y he revisado esa lista muchas, muchas veces.

Las características que existen y que no se usan en un idioma, y ​​que nunca se solicitan en otro, son candidatos poco probables para ingresar a los lenguajes de programación modernos. Sobre todo cuando no hay suficiente tiempo y esfuerzo y dinero disponible en el presupuesto para hacer que las características que las personas no quieren.

Eric Lippert
fuente
IMP vuelve como operador a los días de GWBASIC. Lo recuerdo de 1979.
zarchasmpgmr
1
He leído que IMPL es muy útil para los contratos de código. (Que VB no tenía.)
Mason Wheeler
3
Los programadores de VBScript fueron probablemente el grupo con menos probabilidades de utilizar dicho operador. En este momento, deseo que PowerShell tenga un operador implícito para poder implementar de manera más fácil y legible algunos [switch]parámetros de filtro.
brianary
Recuerdo IMP de DEC BASIC. No recuerdo EQV. El operador que siempre he deseado sería "y no", lo que promovería al operador de la derecha antes de negarlo. Por 0xABCD12345678ul ~& 0x00200000ulo tanto, produciría 0xABCD12145678ul en lugar de 0x12145678ul.
supercat
19

Solo puedo adivinar, pero una razón podría ser que hay soluciones que son bastante simples y legibles. Consideremos su ejemplo:

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

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

Si necesita una expresión, se puede usar el operador en línea disponible en la mayoría de los idiomas (a menudo llamado operador ternario). De acuerdo, esto no es tan elegante como A --> B, pero el número de casos de uso podría no justificar la adición (¡y el mantenimiento!) De otro operador:

assert (mode != ECB ? iv != null : true);
Heinzi
fuente
2
A partir de afirma - hay una buena razón. El primero producirá (en muchas implementaciones) el mensaje "fallo de aserción: iv! = Nulo" mientras que el segundo "fallo de aserción: modo! = BCE -> iv! = Nulo".
Maciej Piechotka
2
+1, estaba a punto de hacer esta misma pregunta sobre la pregunta (dado que no estoy muy familiarizado con la "implicación", nunca surge día a día). La ifdeclaración es mucho, mucho más clara para casi todos.
Izkata
12

Eiffel tiene implicaciones

En realidad tiene aún más. Tiene una serie de operadores semi-estrictos, así como estrictos.

La razón por la que los programadores no usan tales cosas es porque nunca están capacitados para saber exactamente qué son, cómo usarlos y cuándo usarlos, así como cómo diseñar con ellos. Debido a que nunca están capacitados, nunca lo solicitan a los escritores del compilador, por lo que la gente del compilador no se molesta en poner tales mecanismos en el compilador. Cuando los estudiantes de informática y los programadores de Shade-tree comienzan a obtener una educación más completa, los compiladores comenzarán a ponerse al día.

Resulta que una vez que tienes un lenguaje con tales operadores booleanos y sabes cómo diseñar con ellos y usarlos, entonces los usas.

En Eiffel, el uso de la palabra clave "implica" es bastante prominente debido al diseño por contrato debido a la naturaleza booleana de las afirmaciones contractuales. Hay algunos contratos que solo se pueden escribir de manera adecuada y eficiente con el operador "implica". Luego, esto plantea el comentario de que los idiomas sin contrato son más alentadores sin motivo para mirar, entrenar e implementar el uso de la implicación.

Agregue a esto que la mayoría de los programadores son "débiles en matemática y lógica", nos dice el resto de la historia. Incluso si usted es matemático y lógico en su educación, cuando uno elige un lenguaje que no implementa construcciones como la implicación, entonces uno tiende a pensar que tales cosas son innecesarias o no útiles. Uno rara vez cuestiona el lenguaje y se mete en una cámara de eco de: "Bueno, los compiladores no ven la necesidad" y "Bueno, los programadores no ven la necesidad": círculo infinito y vicioso.

En cambio, las personas compiladoras necesitan respaldar la teoría, escribir una notación de lenguaje sugerida o implícita por la teoría (por ejemplo, la Teoría Orientada a Objetos) independientemente de lo que piensen o pidan las masas de programadores. A partir de ahí, los profesores, los maestros y otros profesionales deben capacitar de manera experta a los jóvenes en mente basados ​​en la teoría cruda y NO en la "teoría a través del lente del lenguaje". Cuando esto sucede, las personas se despiertan de repente y se dan cuenta de lo que se han perdido y de lo que se les ha impuesto.

En este momento, hay tanta teoría por ahí que se disfraza de Orientada a Objetos, pero es solo OO-a través de un vidrio-oscuro-de- [elige tu idioma]. No se pueden leer la mayoría de los libros de "teoría" sobre OO porque quieren interpretar cuál es la teoría a través de la lente de algún lenguaje. Totalmente falso e incorrecto. Sería como enseñar matemáticas basadas en mi calculadora o mi regla de cálculo. NO, uno permite que la realidad le enseñe a uno mismo y luego usa una notación para describir lo que uno observa, eso se llama "ciencia". Esta otra mezcla llamada OO-based-on-language-X está tan sesgada que apenas representa la realidad.

Entonces, aléjese del lenguaje, eche un vistazo a la teoría en bruto y comience nuevamente. No permita que las limitaciones, restricciones y trabajos de pintura de un idioma le digan cuál es la teoría. Simplemente deje que la realidad de la teoría dicte su propia notación y luego pase de allí a formular un lenguaje.

A partir de ahí, comenzará a comprender cómo la implicación e "implica" no solo es útil, ¡sino elegante y muy genial!

¡Que tenga uno genial!

Larry
fuente
7

Python tiene un operador de implicación de una manera oculta.

El operador menor que o igual es sobrecargado para aceptar valores booleanos. Como resultado, uno puede usarlo como un operador de implicación.

Prueba por ejemplo (código 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.

Recordemos que la tabla de verdad del operador de implicación es:

LEFT RIGHT RESULT
F    F     T
F    T     T
T    F     F
T    T     T
Mackenzie
fuente
2
Esto es impresionante, pero desafortunadamente tiene las propiedades de rigor incorrectas: f() implies g()no debe evaluar g()si f()es así False, pero <=sí evalúa g()en este caso.
Jon Purdy
2
@ Jon Purdy: estrictamente hablando, la evaluación de cortocircuito es una característica opcional de los operadores binarios. Técnicamente, esta es una implementación perfectamente legítima del operador de implicación. Dicho esto, realmente dudo que Guido van Rossum incluso pretendiera que esto fuera un operador de implicación. Esto es solo una peculiaridad de comparar booleanos.
Mackenzie
Claro, estaba diciendo que es una observación interesante, pero no es algo que deba usar en programas reales porque no está en corto circuito y eso podría sorprender a alguien si espera did_all_possible_stuff = x.do_required_stuff() and (x.supports_optional_stuff() <= x.do_optional_stuff())que funcione.
Jon Purdy
2
Esto funciona en C y C ++ también.
Ben Voigt
5

Eiffel tiene un operador "implica" y es muy bueno para escribir condiciones previas y posteriores. Hace que el código sea más legible, desafortunadamente esa nunca fue una intención fundamental para el lenguaje C y muy pocas personas usaron eiffel, por lo que no se conoce bien la belleza de "implica" como operador.

Lothar
fuente
2

Para mí, el gran problema con implica viene cuando la condición inicial es falsa; por ejemplo: "Si el sol es verde, entonces soy un murciélago de la fruta". ¡Cierto!

En la lógica formal, solo funciona para asignar "Verdadero" al valor cuando no se cumple la condición de la implicación. Pero en la programación, eso podría conducir a resultados contraintuitivos y sorprendentes.

De hecho, creo que el ejemplo que @Heinzi da arriba:

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

Es mucho más fácil de entender y menos propenso a errores debido a malentendidos en la lógica.

En el contexto de las pruebas, simplemente detendría el momento en que mis suposiciones se volvieran falsas:

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

Entonces, para el punto de @Eric Lippert, como programador no sé cuándo usaría un operador implica. El comportamiento "Falso es verdadero" parece útil en el contexto de la lógica matemática formal, pero podría conducir a resultados inesperados en la lógica del programa.

...

Nadie ha mencionado el común "?" operador, donde "A? B: verdadero" es lo mismo que "implica". Pero mientras que la lógica formal asigna fiel a la condición "más", "?" permite al desarrollador asignar eso explícitamente.

En la lógica formal, el uso de "verdadero" funciona, pero en la programación, si la condición es falsa, entonces la mejor respuesta es más como "nulo" o "nulo" o "omitir", o incluso tal vez falso.

Creo que alguien tendría que explicar por qué "implica" es un operador más útil que "?" O "if", o simplemente el flujo regular del programa.

Robar
fuente