<div dir="ltr"><div>Hola, José Luis:</div><div><br></div><div>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 <span style="font-family:monospace">reduce</span> dejara de estar en <span style="font-family:monospace">builtins</span> y acabara en el módulo <span style="font-family:monospace">functools</span>. <br></div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>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".<br></div><div><br></div><div>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.<br></div><div><br></div><div>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í.<br></div><div><br></div><div>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.<br></div><div><br></div><div><br></div><div>Saludos.</div><div><br></div></div><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">El lun, 11 ene 2021 a las 21:18, Jose Luis (<<a href="mailto:jleahred@gmail.com" target="_blank">jleahred@gmail.com</a>>) escribió:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div></div><div>Una pequeña observación.</div><div><br></div><div>Güido ha explicado de forma brillante y coherente en alguna ocasión, que Python no es ni pretende ser "muy" funcional<br></div><div><br></div><div>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</div><div>Pero eso no va en contra de la transparencia referencial.</div><div><br></div><div>Las lambdas de Haskell capturan "cosas" y es muy raro que rompan la transparencia referencial.</div><div><br></div><div>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 ;-)<br></div><div><br></div><div>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</div><div>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) ;-)<br></div><div><br></div><div>Reitero que no tengo claro que forzar "mucho" la programación funcional en Python sea buena idea.</div><div>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)<br></div><div><br></div><div><br></div><div>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 ;-)<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Jan 6, 2021 at 5:31 PM Chema Cortes <<a href="mailto:pych3m4@gmail.com" target="_blank">pych3m4@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div style="font-family:georgia,serif;font-size:large"></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">El mar, 5 ene 2021 a las 16:19, Jesus Cea (<<a href="mailto:jcea@jcea.es" target="_blank">jcea@jcea.es</a>>) escribió:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 4/1/21 11:18, Chema Cortes wrote:<br>
> La recursividad en python es muy limitada. Pero lo que viene a descubrir <br>
> es algo que se podría haber hecho mejor con generadores. En cuanto al <br>
> otro uso, sería una aplicación parcial de argumentos (functools.partial).<br>
> <br>
> Aún así, hay algoritmos recursivos que no son tan fácilmente <br>
> transcribibles en iterables.<br>
<br>
Más allá del uso chorras para convertir una función concreta de <br>
recursiva a iterativa, para mí lo interesante del artículo es el uso de <br>
"closures" para generar funciones personalizadas que se llevan su estado <br>
consigo. No todo necesita el coste de crear clases e instancias <br>
explícitas, no todo se puede solucionar con generadores y <br>
"functools.partial()" no proporciona estado mutable.<br>
<br>
El uso de "closures" explícitos me parece algo que vale la pena añadir a <br>
la caja de herramientas, siempre vigilando que no existe una forma más <br>
elegante de hacer algo concreto.<br>
<br></blockquote><div><br></div><div><div style="font-family:georgia,serif;font-size:large">Aunque suene bien que las funciones mantengan su propio estado, nunca es aconsejable que las funciones tengan efectos colaterales (violación de la <a href="https://en.wikipedia.org/wiki/Referential_transparency" target="_blank">transparencia referencial</a>).<br></div><br></div><div></div><div><div style="font-family:georgia,serif;font-size:large">Las clausuras son importantes y están en el fondo de muchos recursos como pueden ser los <i>decoradores</i>. Pero es siempre posible crear un generador (<span style="font-family:monospace">Iterable</span>) en lugar de una función con clausura (<span style="font-family:monospace">Callable</span>). La diferencia es que los generadores están <i>protocolizados</i>, con opciones para poner fin a la iteración (<span style="font-family:monospace">StopIteration</span>), para inyectar datos a la clausura (método <span style="font-family:monospace">.send()</span>) o para destruir el generador (<span style="font-family:monospace">GeneratorExit</span>). También se pueden usar en gran parte de la librería estándar, con las funciones de itertools como las más potentes.<br></div><div style="font-family:georgia,serif;font-size:large"><br></div><div style="font-family:georgia,serif;font-size:large">Por comparar, la función de fibonacci como generador:</div><div style="font-size:large"><span style="font-family:monospace"><br></span></div><div><font size="2"><span style="font-family:monospace">from itertools import islice</span></font></div><div><font size="2"><span style="font-family:monospace"><br></span></font></div><div><font size="2"><span style="font-family:monospace">def fib():</span></font></div><div><font size="2"><span style="font-family:monospace"> a, b = 1, 1</span></font></div><div><font size="2"><span style="font-family:monospace"> while True:</span></font></div><div><font size="2"><span style="font-family:monospace"> yield a</span></font></div><div style="font-family:georgia,serif"><font size="2"><span style="font-family:monospace"> a, b = b, a+b</span><br></font></div></div><div><font size="2"><span style="font-family:monospace"></span></font></div><span class="gmail_default" style="font-family:georgia,serif;font-size:large"></span><pre><font size="2"><span id="gmail-m_-2630406724792469497gmail-m_-4408561343120797913gmail-m_-7213667193729054652gmail-7ce0">def fib_<span class="gmail_default">generator</span>(n):<br> <span class="gmail_default">return next(islice(fib(), n-1, None))</span></span></font></pre></div><div class="gmail_quote"><br></div><div class="gmail_quote"><div style="font-family:georgia,serif;font-size:large">Si se compara, es casi el doble de rápida que la que viene en el artículo, <span style="font-family:monospace">fib_closure</span>.</div><div style="font-family:georgia,serif;font-size:large"><br></div></div><div class="gmail_quote"><div style="font-family:georgia,serif;font-size:large">Saludos.</div><br><div><span style="font-family:georgia,serif"> </span></div></div>-- <br><div dir="ltr"><div dir="ltr"><div>Hyperreals *R "Quarks, bits y otras criaturas infinitesimales": <a href="https://blog.ch3m4.org" target="_blank">https://blog.ch3m4.org</a><br>Buscador Python Hispano: <a href="https://blog.ch3m4.org/pages/busqueda-python-es/" target="_blank">http://busca.ch3m4.org</a></div></div></div></div></div></div>
_______________________________________________<br>
Asociación Python España: <a href="http://www.es.python.org/" rel="noreferrer" target="_blank">http://www.es.python.org/</a><br>
Python Madrid: <a href="http://www.python-madrid.es/" rel="noreferrer" target="_blank">http://www.python-madrid.es/</a><br>
Madrid mailing list<br>
<a href="mailto:Madrid@lists.es.python.org" target="_blank">Madrid@lists.es.python.org</a><br>
<a href="https://lists.es.python.org/listinfo/madrid" rel="noreferrer" target="_blank">https://lists.es.python.org/listinfo/madrid</a><br>
</blockquote></div>
</blockquote></div></div>