range python 3
Uso de OR como control de rama en FP (6)
Puede considerarse "funcional" en el sentido del estilo de programación que se prefirió en el lenguaje funcional. De lo contrario, no hay nada funcional.
Es solo la sintaxis.
A veces puede ser más fácil de usar o, por ejemplo:
def foo(bar=None): bar = bar or [] ... return bar def baz(elems): print "You have %s elements." % (len(elems) or "no")
Podrías usar bar if bar else []
, pero es bastante elaborado.
Realicé una entrevista la semana pasada en la que aprendí algunas cosas sobre Python que no sabía (o más bien me di cuenta de cómo podrían usarse), primero, y el contenido de esta pregunta es el uso de or
para los fines de las sucursales. controlar.
Así, por ejemplo, si corremos:
def f():
# do something. I''d use ... but that''s actually a python object.
def g():
# something else.
f() or g()
Luego, si f()
evalúa en alguna condición verdadera, entonces ese valor se devuelve, si no, se evalúa g()
y se devuelve el valor que produce, ya sea verdadero o falso. Esto nos da la capacidad de implementar una sentencia if
utilizando or
palabras clave.
También podemos usar and
tal que f() and g()
devolverá el valor de g()
si f()
es verdadero y el valor de f()
si g()
es falso.
Me dicen que esto (el uso de or
para el control de sucursales) es algo común en idiomas como lisp (de ahí la etiqueta lisp). Actualmente estoy siguiendo el SICP aprendizaje SICP , así que puedo ver que (or (fx) (gx))
devolvería el valor de (gx)
asumiendo que (fx)
es #f
.
Estoy confundido en cuanto a si hay alguna ventaja de esta técnica. Claramente, logra el control de la rama, pero para mí, las palabras clave integradas parecen más autoexplicativas.
También estoy confundido en cuanto a si esto es o no "funcional"? Mi comprensión de la programación funcional pura es que utiliza construcciones como esta (un ejemplo de mis recientes experimentos de erlang):
makeeven(N,1) -> N+1;
makeeven(N,0) -> N;
makeeven(N) -> makeeven(N,N rem 2).
O un ejemplo mejor y más complicado que usa la meta-programación de plantillas en C ++ (descubierta a través de cpp-next.com). Mi proceso de pensamiento es que un aspecto de la programación funcional se reduce al uso de funciones definidas por partes en el código para el control de sucursales (y, si se puede administrar, la recursión de la cola).
Entonces, mis preguntas:
- ¿Es esto "funcional"? Parece que de esa manera y mis entrevistadores dijeron que tenían antecedentes en programación funcional, pero no coincidía con lo que yo pensaba que era funcional. No veo ninguna razón por la que no pueda tener un operador lógico como parte de una función: parece prestarse muy bien al concepto de funciones de orden superior. Simplemente no había pensado que el uso de operadores lógicos fuera la forma en que los programadores funcionales lograban el control de sucursales. ¿Derecha? ¿Incorrecto? Puedo ver que los circuitos usan puertas lógicas para el control de bifurcación, así que supongo que este es un concepto similar (relacionado).
- ¿Hay alguna ventaja al usar esta técnica? ¿Es solo cuestión de concisión de lenguaje / sintaxis, o hay implicaciones en términos de construir un intérprete para usar este constructo?
- ¿Existen casos de uso para esta técnica? ¿O no se usa muy a menudo? ¿Se utiliza en absoluto? Como un tipo autodidacta, nunca lo había visto, aunque eso no es necesariamente sorprendente.
Pido disculpas por saltar sobre tantos idiomas; Simplemente estoy tratando de unir mi entendimiento a través de ellos. Siéntase libre de responder en cualquier idioma mencionado. También me disculpo si he malinterpretado alguna definición o me estoy perdiendo algo vital aquí, nunca he estudiado formalmente la informática.
Como dijo Eli; Además, realizar el flujo de control exclusivamente con operadores lógicos tiende a enseñarse en las clases introductorias de PF, más como un ejercicio mental, en realidad, no como algo que necesariamente quiere usar IRL. Siempre es bueno poder traducir cualquier operador de control a if
.
Ahora, la gran diferencia entre los FP y otros lenguajes es que, en lenguajes más funcionales, if
realidad es una expresión, no una declaración. Un bloque if
siempre tiene un valor! La familia de idiomas C tiene una versión macro de esto: ¿la test? consequent : alternative
test? consequent : alternative
construcción test? consequent : alternative
, pero se vuelve realmente ilegible si anida más expresiones.
Antes de Python 2.5, si desea tener una expresión de flujo de control en Python, es posible que tenga que usar operadores lógicos. Sin embargo, en Python 2.5, hay una sintaxis if-expression tipo FP, por lo que puedes hacer algo como esto:
(42 if True else 7) + 35
Ver PEP 308
No tengo conocimiento de ningún problema con la forma en que se ejecutará este código, pero es confuso leerlo para los no iniciados. De hecho, este tipo de sintaxis es como un anti-patrón de Python: puedes hacerlo, pero de ninguna manera es Pythonic.
Solo mencionas el caso donde hay exactamente 2 expresiones para evaluar. ¿Qué pasa si hay 5?
;; returns first true value, evaluating only as many as needed
(or (f x) (g x) (h x) (i x) (j x))
¿Anidarías si-enunciados? No estoy seguro de cómo haría esto en Python. Es casi como esto:
any(c(x) for c in [f, g, h, i, j])
excepto que Python elimina el valor y simplemente devuelve True
. (Puede que haya una manera de hacerlo con itertools.dropwhile
, pero me parece un poco incómodo. O tal vez solo me esté perdiendo la forma obvia).
(Aparte de esto: me parece que los elementos incorporados de Lisp no se corresponden exactamente con sus nombres en otros idiomas, lo que puede ser confuso. El IF
de Lisp es como el operador ternario de C ?:
O las expresiones condicionales de Python, por ejemplo, no su if) Del mismo modo, el OR
de Lisp es en cierto modo más parecido a (pero no exactamente como) el any()
) de Python, que solo toma 2 expresiones. Como el IF
normal ya devuelve un valor, no tiene sentido tener un tipo diferente de "si" que no se puede usar de esta manera, o un tipo separado de "o" que solo toma dos valores. Ya es tan flexible como la variante menos común en otros idiomas).
Resulta que estoy escribiendo un código como este ahora mismo, casualmente, donde algunas de las funciones son "ir a pedirle una respuesta al servidor", y quiero detenerme tan pronto como reciba una respuesta positiva. Nunca usaría OR
donde realmente quiero decir IF
, pero prefiero decir:
(setq did-we-pass (or (try-this x)
(try-that x)
(try-some-other-thing x)
(heck-maybe-this-will-work x))
Que hacer un gran árbol de las FIs. ¿Eso califica como "control de flujo" o "funcional"? Supongo que depende de tus definiciones.
Sus entrevistadores deben haber tenido un "fondo funcional" de regreso. Solía ser común escribir
(or (some-condition) (some-side-effect))
pero en CL y en la implementación del Esquema que lo soporta, está mucho mejor escrito con unless
. Lo mismo vale para and
contra when
.
Entonces, para ser más concretos, no es más funcional (y de hecho, el uso común de estas cosas fue para condicionales unilaterales, que para empezar no son funcionales); no hay ninguna ventaja (lo que se vuelve muy obvio en estos idiomas cuando se sabe que las cosas se implementan como macros, por ejemplo, la mayoría de las implementaciones se expanden a if
); y cualquier caso de uso posible debería usar when
ya unless
si los tenga en su implementación, de lo contrario es mejor definirlos como macros que no usarlos.
Ah, y podrías usar una combinación de ellos en lugar de dos caras if
, pero eso sería muy feo.
condition and true_branch or false_branch
funcionan en todos los idiomas que tienen operadores lógicos de circulación corta. Por otro lado, no es realmente una buena idea utilizarlo en un lenguaje donde los valores tengan un valor booleano.
Por ejemplo
zero = (1==0) and 0 or 1 # (1==0) -> False
zero = (False and 0) or 1 # (False and X) -> X
zero = 0 or 1 # 0 is False in most languages
zero = False or 1
zero = 1