Recientemente, me encontré con un problema que me obligaba a definir el operador lógico "OR" mediante programación, pero sin usar el operador en sí.
Lo que se me ocurrió es esto:
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
¿Es correcta esta lógica o me perdí algo?
programming-logic
logicNoob
fuente
fuente
return arg1 ? arg1 : arg2;
or
operador.Respuestas:
Yo diría que es correcto, pero ¿no podrías condensarlo en algo como esto?
Como estás haciendo una comparación, no creo que realmente necesites verificar la combinación. Solo importa si uno de ellos es verdadero para volverlo verdadero. De lo contrario, queremos devolver falso.
Si está buscando una versión más corta que sea menos detallada, esto también funcionará:
fuente
if arg2 == true
).or(a, b): a ? a : b
Aquí hay una solución sin o, y, no, comparaciones y literales booleanos:
Probablemente no sea mucho más fundamental que eso;)
fuente
true
ofalse
.||
Operador de JavaScript en pocas palabras (cuando se implementa en un lenguaje de tipo dinámico).Una línea de código:
Sin ramificaciones, sin OR.
En un lenguaje basado en C, sería:
Esto es simplemente una aplicación de las leyes de De Morgan :
(A || B) == !(!A && !B)
fuente
if/else
construcción es lo mismo que usar OR, solo que con un nombre diferente.if
es equivalente a la igualdad. Normalmente, en el código de máquina, unif
se implementa como aritmética seguido de una comparación a cero con un salto.and
, proporcionando así consistencia entre los operadores.if (a) return true; else if (b) return true;
parece más o menos moralmente equivalente aif (a OR b) return true;
, pero esa opinión puede estar abierta a disputas.Si solo tiene
and
ynot
, puede usar la ley de DeMorgan para cambiarand
:... o (aún más simple)
...
Y dado que aparentemente todos nos hemos obsesionado con la optimización de algo que casi siempre está disponible como una instrucción de máquina, eso se reduce a:
etc. etc. etc. etc.
Como la mayoría de los idiomas proporcionan un condicional y, las probabilidades son el operador "y" implica una rama de todos modos.
...
Si todo lo que tienes es
nand
(ver wikipedia ):return nand (nand (arg1, arg1), nand (arg2, arg2))
fuente
return not (not arg1 and not arg2)
nand
solución pura .Funciones (ECMAScript)
Todo lo que necesita son definiciones de funciones y llamadas a funciones. No necesita ninguna ramificación, condicionales, operadores o funciones integradas. Demostraré una implementación usando ECMAScript.
Primero, definamos dos funciones llamadas
true
yfalse
. Podríamos definirlos de la forma que queramos, son completamente arbitrarios, pero los definiremos de una manera muy especial que tiene algunas ventajas como veremos más adelante:tru
es una función con dos parámetros que simplemente ignora su segundo argumento y devuelve el primero.fls
También es una función con dos parámetros que simplemente ignora su primer argumento y devuelve el segundo.¿Por qué codificamos
tru
y defls
esta manera? Bueno, de esta manera, las dos funciones no solo representan los dos conceptostrue
yfalse
, no, al mismo tiempo, también representan el concepto de "elección", en otras palabras, ¡también son una expresiónif
/then
/else
! Evaluamos laif
condición y le pasamos elthen
bloque y elelse
bloque como argumentos. Si la condición se evalúa comotru
, devolverá elthen
bloque, si se evalúa comofls
, devolverá elelse
bloque. Aquí hay un ejemplo:Esto vuelve
23
, y esto:vuelve
42
, tal como es de esperar.Sin embargo, hay una arruga:
Esto imprime ambos
then branch
yelse branch
! ¿Por qué?Bueno, devuelve el valor de retorno del primer argumento, pero evalúa ambos argumentos, ya que ECMAScript es estricto y siempre evalúa todos los argumentos de una función antes de llamar a la función. IOW: evalúa el primer argumento que es
console.log("then branch")
, que simplemente regresaundefined
y tiene el efecto secundario de imprimirthen branch
en la consola, y evalúa el segundo argumento, que también regresaundefined
e imprime en la consola como un efecto secundario. Luego, devuelve el primeroundefined
.En el cálculo λ, donde se inventó esta codificación, eso no es un problema: el cálculo λ es puro , lo que significa que no tiene efectos secundarios; por lo tanto, nunca notarías que el segundo argumento también se evalúa. Además, el cálculo λ es perezoso (o al menos, a menudo se evalúa en orden normal), lo que significa que en realidad no evalúa argumentos que no son necesarios. Entonces, IOW: en el cálculo λ, el segundo argumento nunca sería evaluado, y si lo fuera, no lo notaríamos.
ECMAScript, sin embargo, es estricto , es decir, siempre evalúa todos los argumentos. Bueno, en realidad, no siempre: el
if
/then
/else
, por ejemplo, solo evalúa lathen
rama si la condición estrue
y solo evalúa laelse
rama si la condición esfalse
. Y queremos replicar este comportamiento con nuestroiff
. Afortunadamente, a pesar de que ECMAScript no es perezoso, tiene una forma de retrasar la evaluación de un fragmento de código, de la misma manera que lo hace casi cualquier otro idioma: envolverlo en una función, y si nunca llama a esa función, el código lo hará Nunca ser ejecutado.Entonces, envolvemos ambos bloques en una función, y al final llamamos a la función que se devuelve:
impresiones
then branch
yimpresiones
else branch
.Podríamos implementar el
if
/then
/ tradicional deelse
esta manera:Nuevamente, necesitamos un ajuste de función adicional al llamar a la
iff
función y los paréntesis de llamada de función adicional en la definición deiff
, por la misma razón que arriba:Ahora que tenemos esas dos definiciones, podemos implementar
or
. Primero, miramos la tabla de verdad paraor
: si el primer operando es verdadero, entonces el resultado de la expresión es el mismo que el primer operando. De lo contrario, el resultado de la expresión es el resultado del segundo operando. En resumen: si el primer operando estrue
, devolvemos el primer operando, de lo contrario devolvemos el segundo operando:Veamos que funciona:
¡Excelente! Sin embargo, esa definición se ve un poco fea. Recuerde,
tru
yfls
ya actúa como un condicional por sí mismo, por lo que realmente no es necesarioiff
y, por lo tanto, toda esa función se ajusta:Ahí lo tiene:
or
(más otros operadores booleanos) definidos con nada más que definiciones de funciones y llamadas de funciones en solo un puñado de líneas:Desafortunadamente, esta implementación es bastante inútil: no hay funciones u operadores en ECMAScript que regresen
tru
ofls
, todos regresantrue
ofalse
, por lo que no podemos usarlos con nuestras funciones. Pero todavía hay mucho que podemos hacer. Por ejemplo, esta es una implementación de una lista vinculada individualmente:Objetos (Scala)
Es posible que haya notado algo peculiar:
tru
yfls
desempeñan un doble papel, actúan como valores de datostrue
yfalse
, al mismo tiempo, también actúan como una expresión condicional. Son datos y comportamiento , agrupados en un ... uhm ... "cosa" ... ¡u (me atrevo a decir) objeto !De hecho,
tru
yfls
son objetos. Y, si alguna vez ha utilizado Smalltalk, Self, Newspeak u otros lenguajes orientados a objetos, habrá notado que implementan booleanos exactamente de la misma manera. Demostraré tal implementación aquí en Scala:Por cierto, la refactorización Reemplazar condicional por polimorfismo siempre funciona: siempre puede reemplazar todos y cada uno de los condicionales en su programa con envío de mensajes polimórficos, porque como acabamos de mostrar, el envío de mensajes polimórficos puede reemplazar condicionales simplemente implementándolos. Idiomas como Smalltalk, Self y Newspeak son prueba de la existencia de eso, porque esos idiomas ni siquiera tienen condicionales. (Tampoco tienen bucles, por cierto, o realmente ningún tipo de estructuras de control incorporadas en el lenguaje, excepto el envío de mensajes polimórficos, también llamadas de método virtual).
Coincidencia de patrones (Haskell)
También podría definir el
or
uso de la coincidencia de patrones, o algo así como las definiciones de funciones parciales de Haskell:Por supuesto, la coincidencia de patrones es una forma de ejecución condicional, pero, de nuevo, también lo es el envío de mensajes orientado a objetos.
fuente
False ||| False = False
y en su_ ||| _ = True
lugar? :)True ||| undefined
en ghci para ver!Aquí hay otra forma de definir OR, o de hecho cualquier operador lógico, usando la forma más tradicional de definirlo: use una tabla de verdad.
Por supuesto, esto es bastante trivial en lenguajes de nivel superior como Javascript o Perl, pero estoy escribiendo este ejemplo en C para mostrar que la técnica no depende de las características del lenguaje de alto nivel:
Puede hacer lo mismo con AND, NOR, NAND, NOT y XOR. El código es lo suficientemente limpio como para parecerse a la sintaxis, de modo que puede hacer cosas como esta:
fuente
BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));
Otra forma de expresar los operadores lógicos como expresiones aritméticas de enteros (cuando sea posible). De esta manera puede evitar muchas ramificaciones para una expresión más amplia de muchos predicados.
Deje que True sea 1 Deje que False sea 0
Si la suma de ambos es mayor que 1, es verdadero o falso ser devuelto.
fuente
booleanExpression ? true : false
es trivialmente igual abooleanExpression
.return (arga+argb)>0
return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0);
:)arg1 ? 1 : 0;
. Esas son expresiones confiables para transformar un booleano en un número. Es solo la declaración de devolución la que se puede refactorizar trivialmente.Las dos formas:
O
Además del código, tiene la ventaja de ser un poco más pequeño que las otras sugerencias hasta ahora, una rama menos. Ni siquiera es tan tonto una microopción para reducir el número de ramas si consideramos la creación de una primitiva que, por lo tanto, se usaría mucho.
La definición de Javascript de
||
es similar a esto, lo que combinado con su escritura suelta significa que la expresiónfalse || "abc"
tiene el valor"abc"
y42 || "abc"
tiene el valor42
.Sin embargo, si ya tiene otros operadores lógicos, los gustos de
nand(not(arg1), not(arg2))
podría tener la ventaja de no tener ninguna ramificación.fuente
Además de todas las soluciones programadas que utilizan la construcción if, es posible construir una puerta OR combinando tres puertas NAND. Si quieres ver cómo se hace en wikipedia, haz clic aquí .
De esto, la expresión,
que usa NOT y AND da la misma respuesta que OR. Tenga en cuenta que el uso de NOT y AND es solo una forma oscura de expresar NAND.
fuente
Todas las buenas respuestas ya han sido dadas. Pero no dejaré que eso me detenga.
Alternativamente:
Espero que nadie use enfoques como estos. Están aquí solo para promover el conocimiento de las alternativas.
Actualizar:
Dado que los números negativos pueden romper los dos enfoques anteriores, aquí hay otra sugerencia horrible:
Esto simplemente usa las Leyes de DeMorgan y abusa del hecho que
*
es similar a&&
cuándotrue
yfalse
son tratados como1
y0
respectivamente. (Espera, ¿estás diciendo que esto no es código golf?)Aquí hay una respuesta decente:
Pero eso es esencialmente idéntico a otras respuestas ya dadas.
fuente
arg1+arg2
, -1 y 0 paramax(arg1,arg2)
, etc.Una forma de definir
or
es a través de una tabla de búsqueda. Podemos hacer esto explícito:creamos una matriz con los valores que debe tener el valor de retorno dependiendo de lo que
a
sea. Luego hacemos una búsqueda. En lenguajes similares a C ++, sebool
promueve a un valor que puede usarse como un índice de matriz, contrue
ser1
yfalse
ser0
.Luego podemos extender esto a otras operaciones lógicas:
Ahora, una desventaja de todo esto es que requiere notación de prefijo.
y ahora puedes escribir
true *OR* false
y funciona.La técnica anterior requiere un lenguaje que admita búsquedas dependientes de argumentos y plantillas. Probablemente podría hacerlo en un idioma con genéricos y ADL.
Como comentario, puede extender lo
*OR*
anterior para trabajar con conjuntos. Simplemente cree una función libreinvoke
en el mismo espacio de nombres queor_tag
:y ahora
set *OR* set
devuelve la unión de los dos.fuente
Este me recuerda las funciones de carácter:
Esto solo se aplica a los idiomas que pueden tratar booleanos como (1, 0). No se aplica a Smalltalk o Python ya que boolean es una clase. En smalltalk van aún más lejos (esto se escribirá en una especie de pseudocódigo):
Y existen los métodos duales para y:
Por lo tanto, la "lógica" es perfectamente válida en la declaración OP, aunque es detallada. Cuidado, no está mal. Es perfecto si necesita una función que actúa como un operador matemático basado, por ejemplo, en un tipo de matriz. Otros implementarían un cubo real (como una declaración de Quine-McCluskey):
Y usted evaluará o [a] [b]
Entonces, sí, cada lógica aquí es válida (excepto la publicada como que usa el operador OR en lenguaje xDDDDDDDD).
Pero mi favorita es la ley de DeMorgan:
!(!a && !b)
fuente
Mire la biblioteca estándar de Swift y compruebe su implementación del acceso directo OR y las operaciones de acceso directo AND, que no evalúan los segundos operandos si no son necesarios / permitidos.
fuente
La lógica es perfectamente correcta, pero se puede simplificar:
Y presumiblemente su idioma tiene un operador OR, así que, a menos que esté en contra del espíritu de la pregunta, ¿por qué no?
fuente
if arg1 = True or arg2 = True { return true } else { return false }
Mejor aún,return arg1 = True or arg2 = True
.if condition then true else false
es redundante