This commit is contained in:
Vladimir Lemus 2023-02-26 10:41:02 -06:00
parent 283a5234c6
commit 12f7e30ce3
2 changed files with 72 additions and 18 deletions

Binary file not shown.

View File

@ -343,18 +343,41 @@ Vamos ahora a expresar una función $\lambda$ en su forma más simple y pura
\begin{itemize}
\item \textbf{Reducción $\alpha$}: Renombrar variables. Se dice que dos funciones son $\alpha equivalentes$ cuando lo único que cambia es el nombre d ela variable ($\lambda x.(x+1)$ y $\lambda a.(a+1)$).
\item \textbf{Reducción $\beta$}: Remplaza variables por argumentos. Como ya hicimos líneas arriba.
\item \textbf{Reducción $\eta$}:
\item \textbf{Reducción $\eta$}: Un aso antes para asegurar la reducción $\beta$
\end{itemize}
Un ejemplo de $\alpha$ equivalencia son la pareja de funciones:
\begin{align*}
\lambda x.&(x^2+3x) \\
\lambda a.&(a^2+3a),
\end{align*}
\noindent Si cambiamos el nombre de la variable en ambos casos, tenemos la misma función. Siempre es posible renombrar variables mientras no se use el nombre de una ya utilizada.
La reducción $\beta$ ya viomos un ejemplo, pero para no dejar damos un ejemplo evaluando la función en un natural:
\begin{align*}
\lambda x.&(x^2+3x)(2) \\
&(2^2+3(2)) \\
=& 10,
\end{align*}
\noindent y evaluando en optra función, a final de cuentas variables, constantes y funciones todas son $\lambda$ términos y valen lo mismo para la $\beta$ reducción
\begin{align*}
\lambda x.&(x^2+3x)(\lambda y.(y+1)) \\
&((y+1)^2+3(y+1)),
\end{align*}
La reducción $\eta$ es un paso más abstracto, de cierta manera se asegura de que la forma de la función $\lambda$ es correcta y está lista para una $\beta$ reducción. A este punto no es necesario ahondar mucho en ello.
\section*{Programación funcional en \emph{Python}}
Declaraciones en lugar de procedimientos paso a paso.
Una de las características de la programación funcional a diferencia de la programación estructurada o la orientada a objetos es que funciona a partir de declaraciones en lugar de procedimientos paso a paso. Es decir, le decimos a la máquina que hacer pero no le indicamos como hacerlo. Así funciona Haskell por diseño, con la ya comentada ventaja de los datos inmutables (evitando los problemas de flujo de datos en concurrencia, como mencionamos la sección pasada).
Le decimos que hacer pero no como hacerlo.
Haskell: datos inmutables
Vemos en python:
¿Cómo es eso de los datos inmutables? Vemos en python:
\begin{lstlisting}{language=Python}
x=1
@ -363,22 +386,24 @@ Vemos en python:
id(x)==oldID
\end{lstlisting}
El valor ha mutado, pues lo hemos obligado a hacerlo así, pero en un caso más amplio si no somos cuidadosos podría provocar errores en nuestro programa.
La falta de estado, como sucede en Haskell, conlleva la desventaja de la falta de memoria.
\section*{Funciones en Haskell}
Dos opciones, \emph{curriado} y \emph{no curriado}.
En Haskell existen dos opciones para definir funciones, de forma \emph{curriada} y \emph{no curriada} (por Haskell Curry, no porque le pongamos ese condimento de la comida oriental).
La definición de una *non-curried*
La definición de una función \emph{no curriada}
\begin{lstlisting}{language=Haskell}
suma (x,y) = x+y
suma (x,y) = x+y.
\end{lstlisting}
A partir de la función suma definamos la función sucesor:
A partir de esa función suma definamos la función sucesor:
\begin{lstlisting}{language=Haskell}
suc (x) = suma (x,1)
suc (x) = suma (x,1).
\end{lstlisting}
Si esto mismo trataramos de hacer en $python$, para definir una operación que deja sin cambio una variable, se tiene que hacer:
@ -395,13 +420,17 @@ Regresando a Haskell, definamos las operaciones de suma e incremento de forma \e
suma x y = x+y
\end{lstlisting}
Aquí parece que solo quitamos los paréntesis, pero no. Para notar la diferenbcia ahora definimos la función incremento como:
Aquí parece que solo quitamos los paréntesis, pero no. Para notar la diferencia ahora definimos la función incremento como:
\begin{lstlisting}{language=Haskell}
inc = suma 1
\end{lstlisting}
Se puede usar *curry* y *uncurry* para pasar de una a la otra. Aprovecha para jugar con map.
Se puede usar \emph{curry} y \emph{uncurry} para pasar de una a la otra. Aprovecha para jugar con \emph{map}.
\begin{lstlisting}{language=Haskell}
suma_u = uncurry suma
\end{lstlisting}
Como haríamos esto mismo en $python$:
@ -417,14 +446,39 @@ Para definir el incremento en uno:
return suma (x,1)
\end{lstlisting}
Pero apliquemos lo visto anteriormente de cálculo $\lambda$ para ambos lenguajes de programación. En Haskell ya vimos un poco pero ampliemos, para definir una función tenemos tres formas equivalentes
\begin{align*}
suma\ x=& \setminus y -> x+y \\
suma =& \setminus x -> (\setminus y -> x+y) \\
suma =& \setminus x -> \setminus y -> x+y.
\end{align*}
Noten que es como una definición de funciones $\lambda$, en lugar de $\lambda$ se usa $\setminus$ y se sigue la misma estructura. De esta forma puede definirse la suma sin argumentos pero dentro de la definición están los $\lambda$ términos necesarios para aceptar variables.
Al verlo pueden pensar que so no tiene el mayor chiste, más parece que nos complicamos la vida, pero no, esto tiuene un sentido más. ¿Qué tal que quisiéramos definir un nuevo operador, llamémosle $+=$\footnote{Ahora no tiene mucha diferencia al operador $+$ salvo que nosotros lo definimos, pero imaginen aplicar esto para una función más complicada que puede ser evaluada con un simple operador.}?
\begin{align*}
(+=) =& \setminus x -> \setminus y -> x+y\\
(+=) =& \setminus x\ y -> x+y \\
3\ +=\ 5.
\end{align*}
¿Cómo podemos definir funciones $\lambda$ en $python$? Aunque para este lenguaje de programación el cálculo $\lambda$ no está directamente aplicado, está de alguna forma desde sus huesos. Por las características de ser más directamente aplicable. más sencillo, esto sirve más como un caso ilustrativo. Las dos formas de definir una función con cálculo $\lambda$ en $python$:
\begin{align*}
suma =& lambda\ x, y: x+y \\
&suma(3,2) \text{ la forema de llamar a la función}\\
suma =& lambda\ x: lambda\ y: x+y\\
&suma(3)(2) \text{ llamando a la función},
\end{align*}
\noindent vea que las diferentes definiciones en este caso implican llamr de forma distinta a la función. En la definición $\lambda$ se escribe $lambda$.
\begin{thebibliography}{10}
\bibitem{Thompson1996} Thompson, Simon J.. ``Haskell - the craft of functional programming.'' International computer science series (1996).
\bibitem{VanRoy2009} Van Roy, Peter. ``Programming paradigms for dummies: what every programmer should know.'' (2009).
\bibitem{VanRoy2004} Van Roy, Peter, Haridi, Seif. ``Concepts, Techniques, and Models of Computer Programming''. *The MIT Press*, (2004). ISBN: 0262220695
\bibitem{Kowalski1988} Kowalski, Robert. ``The early years of logic programming'',\textit{Communications of the ACM}, \textbf{31}, 1, (1988).
\bibitem{python_concurrency} \url{https://realpython.com/python-concurrency/}, revisado el 15 de febrero de 2023.
\bibitem{Mueller2019} Mueller, John P. ``Functional programming (for dummies)'' John Willey $\&$ Sons Inc. (2019).
\bibitem{Kozen} Kozen, Dexter C. ``Automata and Computability'' Springer (1997)
\end{thebibliography}