[Py-MAD] [Py-ES] Don’t Use Recursion In Python Any More,Python Closure — A Pythonic technique you must know
Jose Luis
jleahred at gmail.com
Tue Jan 12 23:08:55 CET 2021
Respondo a Chema sobre los "closures", capturas y los "side effects"
Uffff, me obligas a ser un poco más simpático y poner alguna url ;-)
El concepto de closure fue "inventado" por Alonzo Church en lambda-cálculus
The concept of closures was developed in the 1960s for the mechanical
evaluation of expressions in the λ-calculus
<https://en.wikipedia.org/wiki/%CE%9B-calculus>
https://en.wikipedia.org/wiki/Closure_(computer_programming)
El cálculo lambda es muy funcional, y muuuuchos conceptos de la
programación fucnional vienen de aquí. De hecho, el lambda-calculus es la
respuesta "funcional" de Church a la idea de la máquina de Turing
(imperativa donde lo haya)
En el cálculo lambda no sólo habla de closures, sino que todo son
"potencialmente" closures ;-)
Con "potencialmente" quiero decir que no necesitas especificarlo, si lo es
o no lo es, depende de si tú capturas o no capturas (y para capturar, sólo
tienes que utilizar, no declarar intenciones)
Y en Haskell, como tantas otras cosas en Haskell, es igual que
lamda-calculus en este punto
Estoy que lo tiro (otra url, en una búsqueda rápida, eso sí)
Esto es sobre haskell...
https://wiki.haskell.org/Closure
Closure
A closure, the opposite of a combinator
<https://wiki.haskell.org/Combinator>, is a function that makes use of free
variables <https://wiki.haskell.org/Free_variable> in its definition. It
'closes' around some portion of its environment. for example
f x = (\y -> x + y)
Para el que no conozca mucho Haskell, el closure es lo que está entre
paréntesis, que es una función lambda, que en este caso, ha capturado la x
y por eso se ha "promocionado a un closure" ;-)
Como veis, igual que en lambda-calculus, si es un "closure" o es un
"combinator" depende de si "capturas" o no
Por cierto el símbolo \ pretende parecerse a una lambda (es lo más
parecido en teclado normal) y eso es lo que es, es una lambda de lambda
cálculus, que "captura" la x que no es un parámeto de la propia lambda (el
parámetro es y, no x)
El logotipo de Haskell, no tiene por casualidad una lambda ;-)
[image: image.png]
Tanto Haskell como lambda-calculus son poco sospechosos de tener "muchos"
"side effects" y ambos tienen "funciones anónimas" que "capturan"
Decías chema...
*Si una misma expresión lambda, ante el mismo argumento da resultados
distintos, entonces el orden en que hagas su evaluación cambia el
resultado. Estaría incumpliendo el principio de transparencia referencial*
Creo que aquí estás pensando en python u otro lenguaje bastante imperativo
donde ciertamente un "closure" muy fácilmente puede provocar "side effects"
(aunque también es muy normal que las "funciones" de python tengan
"efectos"), pero en haskell o lambda-cálculus los closures no pueden añadir
"side effects"
Para añadir "efectos colaterales" tienes que recurrir a un "truco/trampa"
muy específico y nada tiene que ver con los closures
Me extendería mucho más, pero... creo que para una lista de Python, hablar
tan poco de Python... ya me he excedido ;-)
Saludos
On Tue, Jan 12, 2021 at 3:57 PM Francisco José Fernández Naranjo <
fjfnaranjo at gmail.com> wrote:
> Sobre lo que comentas al principio Chema, y sobre lo que dice Guido,
> siempre me resultó curioso una cosa a la que pocas veces se hace
> referencia cuando se habla de este tema.
>
> Tendemos a hablar de ciertas capacidades del lenguaje como si fueran
> aspiracionales. Por ejemplo, a pensar que usar programación funcional
> (o las opciones pseudo-funcionales) es "mejor" (o más pythónico) para
> ciertos casos. Y tendemos por tanto a decidir que cuando alguien no
> usa una característica del lenguaje el problema es de comprensión de
> la característica en sí por su parte (cuando no eres directamente
> condescendiente y piensas que es un inútil). Pero yo lo que me
> encuentro en mi día a día cuando trabajo es un mundo donde la gente
> tiene unas habilidades muy diversas y donde no quieres que todo el
> mundo sea una persona extremadamente capaz en muchas cosas, si no
> donde quieres un grupo de personas que se complementen.
>
> Concretando, bajar al nivel de la programación funcional, sobre todo
> si no se comprende bien de manera no-funcional, va a agregar
> complejidad al código o el diseño que va a repercutir en la capacidad
> de otras personas para leerlo, comentarlo, mantenerlo... Esto aplica
> también a conocimientos específicos, como por ejemplo, operar correcta
> y eficientemente con datos usando cython, o entender como llevar un
> proceso muy complejo a una librería en C para usarla desde Python a
> más alto nivel.
>
> Cuando yo me encuentro con esto, siempre me ha gustado mucho el
> programador que sabe escribir esa complejidad en la parte más profunda
> del diseño, y deja las operaciones más universales en la parte
> superior del mismo. Eso permite simultáneamente combinar la capacidad
> específica de ese programador con los compañeros que no han
> desarrollado tanto en ese área.
>
> Una de las cosas que comentas al final, cuando dices "hay mucho
> potencial en python que no se usa bien o se ignora que está ahí" (y
> donde solapas un poco con la opinión de Guido) deja un poco fuera la
> decisión de ese programador pragmático que saber medir muy bien donde
> poner su aprendizaje y esfuerzo para cumplir simultáneamente con el
> "Simple is better than complex" y con el "Complex is better than
> complicated". Creo que dos figuras en la comunidad de Python que
> representan un poco esta diferencia de apreciación por lo pragmático
> son Guido y Raymond Hettinger. Donde ves por una lado el programador
> que aspira a la belleza en lo "complex" y el que aspira a la belleza
> en lo "simple".
>
> Y en ese caso, creo que es muy acertado la decisión que hasta ahora se
> ha tomado en el diseño de Python de que algunas características tienen
> mejor lugar en paquetes como "functools". Formando parte como dices de
> ese compendio de buenas ideas de otros lenguajes. Y esa "pena" que ves
> al final, se puede ver también como una de las grandes fortalezas del
> lenguaje.
>
> Un saludo,
> Naranjo.
>
>
>
>
> On Tue, Jan 12, 2021 at 2:56 PM Chema Cortés <pych3m4 at gmail.com> wrote:
> >
> > Hola, José Luis:
> >
> > Guido suele decir que las características funcionales de python se usan
> muy poco porque no se llegan a entender. Ese fue el motivo, al menos, para
> que la función reduce dejara de estar en builtins y acabara en el módulo
> functools.
> >
> > El cálculo lambda de Church sí que está relacionado con la transparencia
> referencial, pero no dice nada de clausuras. La idea es que mediante
> "aplicaciones" y "reducciones" transformes una expresión lambda hasta
> llegar a un valor, independientemente del orden en que hagas las
> transformaciones.
> >
> > Si una misma expresión lambda, ante el mismo argumento da resultados
> distintos, entonces el orden en que hagas su evaluación cambia el
> resultado. Estaría incumpliendo el principio de transparencia referencial.
> >
> > Si se encapsula una función con una clausura para mantener estados, los
> resultados de la función podrían ser distintos ante los mismos argumentos.
> No podemos sustituir la llamada a la función por su resultado, por lo que
> se incumple la transparencia referencial. En realidad, solemos decir más
> que la función tiene "efectos colaterales".
> >
> > En haskell, no existen los "contextos" como los llamas. Todo son
> "transformaciones" entre unos valores de entrada y de salida. Para mantener
> "estados" se usan las "transformaciones monádicas", que no son "clausuras".
> No se almacena ningún estado, sólo indicas de qué estado a qué estado
> pasas, sin ninguna persistencia entre llamadas.
> >
> > En cuanto a las características de programación funcional que pueda
> tener python, muy pocos las usan o son conscientes de que las usan. Python,
> junto con su librería estándar, es un compendio de conocimientos aplicados
> que han sido traídos desde otros lenguajes. Mucho de lo que llamamos "modo
> pythónico" de hacer las cosas no son otra cosa que transformaciones
> funcionales con una teoría detrás que ignoramos mayormente: compresiones de
> listas, tipos algebraicos, dataclases, ordenación por clave, etc, etc.En mi
> opinión, hay mucho potencial en python que no se usa bien o se ignora que
> está ahí.
> >
> > Seguro que Guido hace bien en mantener un lenguaje python accesible para
> todos y que no quiera liarla más con conceptos de programación funcional.
> Pero me parece una pena.
> >
> >
> > Saludos.
> >
> >
> >
> > El lun, 11 ene 2021 a las 21:18, Jose Luis (<jleahred at gmail.com>)
> escribió:
> >>
> >> Una pequeña observación.
> >>
> >> Güido ha explicado de forma brillante y coherente en alguna ocasión,
> que Python no es ni pretende ser "muy" funcional
> >>
> >> Los "closures" de Python (hay que matizar, porque cada uno define
> closure como le da la gana), capturan "cosas" (llámalo estado si quieres),
> OK
> >> Pero eso no va en contra de la transparencia referencial.
> >>
> >> Las lambdas de Haskell capturan "cosas" y es muy raro que rompan la
> transparencia referencial.
> >>
> >> De hecho, el concepto closure diría que viene del cálculo lambda (del
> genial "profe" de Turing, Alonzo Church), y simplificando, son funciones
> anónimas (aka lambdas) que capturan y tampoco rompen la transparencia
> referencial (es la gracia del cálculo lambda vs la máquina de Turing ;-)
> >>
> >> Una función lambda con un contexto difernte, es una función diferente.
> Si tú le pones el mismo nombre "mutando" o haces mutaciones del contexto...
> puedes romper la transparencia referencial, pero no es por el concepto de
> "closure" o captura
> >> Vamos, que si capturar "cosas" (aka contexto, aka estado, aka
> variables, aka "llámalo como quieras") violara la transparencia
> referencial, Haskell no sería muy funcional (ni el cálculo lambda) ;-)
> >>
> >> Reitero que no tengo claro que forzar "mucho" la programación funcional
> en Python sea buena idea.
> >> Que yo lo opine, poco valor tiene, pero considero a Güido como un tipo
> coherente y muy inteligente, del que he aprendido un montón de cosas con
> sus reflexiones y explicaciones; y corregidme si me equivoco, pero diría
> que Güido no es partidario de "forzar" python con programación funcional
> (si fuera un tipo más serio y simpático, mandaría los enlaces de Güido al
> respecto, pero los tengo que buscar, estoy cansado y tampoco dispongo de
> tiempo en este momento)
> >>
> >>
> >> Saludos de un humilde amante de la programación funcional (amor no
> correspondido; ni me quiere la programación funcional, ni la imperativa,
> pero sigo dando guerra ;-)
> >>
> >> On Wed, Jan 6, 2021 at 5:31 PM Chema Cortes <pych3m4 at gmail.com> wrote:
> >>>
> >>>
> >>> El mar, 5 ene 2021 a las 16:19, Jesus Cea (<jcea at jcea.es>) escribió:
> >>>>
> >>>> On 4/1/21 11:18, Chema Cortes wrote:
> >>>> > La recursividad en python es muy limitada. Pero lo que viene a
> descubrir
> >>>> > es algo que se podría haber hecho mejor con generadores. En cuanto
> al
> >>>> > otro uso, sería una aplicación parcial de argumentos
> (functools.partial).
> >>>> >
> >>>> > Aún así, hay algoritmos recursivos que no son tan fácilmente
> >>>> > transcribibles en iterables.
> >>>>
> >>>> Más allá del uso chorras para convertir una función concreta de
> >>>> recursiva a iterativa, para mí lo interesante del artículo es el uso
> de
> >>>> "closures" para generar funciones personalizadas que se llevan su
> estado
> >>>> consigo. No todo necesita el coste de crear clases e instancias
> >>>> explícitas, no todo se puede solucionar con generadores y
> >>>> "functools.partial()" no proporciona estado mutable.
> >>>>
> >>>> El uso de "closures" explícitos me parece algo que vale la pena
> añadir a
> >>>> la caja de herramientas, siempre vigilando que no existe una forma más
> >>>> elegante de hacer algo concreto.
> >>>>
> >>>
> >>> Aunque suene bien que las funciones mantengan su propio estado, nunca
> es aconsejable que las funciones tengan efectos colaterales (violación de
> la transparencia referencial).
> >>>
> >>> Las clausuras son importantes y están en el fondo de muchos recursos
> como pueden ser los decoradores. Pero es siempre posible crear un generador
> (Iterable) en lugar de una función con clausura (Callable). La diferencia
> es que los generadores están protocolizados, con opciones para poner fin a
> la iteración (StopIteration), para inyectar datos a la clausura (método
> .send()) o para destruir el generador (GeneratorExit). También se pueden
> usar en gran parte de la librería estándar, con las funciones de itertools
> como las más potentes.
> >>>
> >>> Por comparar, la función de fibonacci como generador:
> >>>
> >>> from itertools import islice
> >>>
> >>> def fib():
> >>> a, b = 1, 1
> >>> while True:
> >>> yield a
> >>> a, b = b, a+b
> >>>
> >>> def fib_generator(n):
> >>> return next(islice(fib(), n-1, None))
> >>>
> >>>
> >>> Si se compara, es casi el doble de rápida que la que viene en el
> artículo, fib_closure.
> >>>
> >>> Saludos.
> >>>
> >>>
> >>> --
> >>> Hyperreals *R "Quarks, bits y otras criaturas infinitesimales":
> https://blog.ch3m4.org
> >>> Buscador Python Hispano: http://busca.ch3m4.org
> >>> _______________________________________________
> >>> Asociación Python España: http://www.es.python.org/
> >>> Python Madrid: http://www.python-madrid.es/
> >>> Madrid mailing list
> >>> Madrid at lists.es.python.org
> >>> https://lists.es.python.org/listinfo/madrid
> >
> > _______________________________________________
> > Asociación Python España: http://www.es.python.org/
> > Python Madrid: http://www.python-madrid.es/
> > Madrid mailing list
> > Madrid at lists.es.python.org
> > https://lists.es.python.org/listinfo/madrid
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.es.python.org/pipermail/madrid/attachments/20210112/6fabaabd/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image.png
Type: image/png
Size: 5748 bytes
Desc: not available
URL: <https://lists.es.python.org/pipermail/madrid/attachments/20210112/6fabaabd/attachment-0001.png>
More information about the Madrid
mailing list