Recientemente, estoy tratando de usar Haskell en algunos de mis sistemas de producción de casos reales. El sistema de tipos Haskell realmente me ofrece una gran ayuda. Por ejemplo, cuando me di cuenta de que necesitaba alguna función de tipo
f :: (Foldable t, Monad m) => ( a-> b -> m b) -> b -> t a -> m b
En realidad, hay funciones como foldM
, foldlM
y foldrM
.
Sin embargo, lo que realmente me sorprendió es la definición de estas funciones, tales como:
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldr f' return xs z0
where f' x k z = f z x >>= k
entonces la función f'
debe ser de tipo:
f' :: a -> b -> b
según lo requerido por foldr
, entonces b
debe ser amable *-> m *
, por lo que toda la definición de foldlM
podría tener sentido.
Otro ejemplo incluye definiciones de liftA2
y<*>
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 id
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<*>) (fmap f x)
Probé algunas de mis propias soluciones antes de mirar el código fuente. Pero la brecha es tan grande que no creo que pueda encontrar esta solución, sin importar cuántas líneas de código escriba en el futuro.
Entonces mi pregunta es, qué tipo de conocimiento o qué rama matemática específica es necesaria para que alguien razone en un nivel tan altamente abstracto.
Sé que la teoría de categorías podría ofrecer algo de ayuda y he estado siguiendo esta gran conferencia durante mucho tiempo y todavía estoy trabajando en ello.
fuente
Respuestas:
En general, lógica, etc., me imagino. Pero también puedes aprenderlo haciéndolo. :) Con el tiempo notas algunos patrones, toma algunos trucos.
Me gusta esto
foldr
con un argumento extra. Algunos lo ven como plegado en funciones para que puedan combinarse.
yid
(que a veces son realmente<=<
yreturn
),A algunos les resulta más fácil entenderlo en términos sintácticos más simples, como
entonces, cuando
g
no es estricto en su segundo argumento,s
puede servir como un estado que se transmite desde la izquierda, aunque estemos doblando a la derecha, como un ejemplo.fuente
Entonces, la mejor manera de entenderlo es hacerlo. A continuación hay una implementación de
foldlM
uso enfoldl
lugar defoldr
. Es un buen ejercicio, pruébalo y luego ve a la solución que sugeriría. El ejemplo explica todo el razonamiento que he hecho para lograrlo, que podría ser diferente al suyo y podría ser parcial porque ya sabía sobre el uso de un acumulador de funciones.Paso 1 : tratemos de escribir
foldlM
en términos defoldl
Aquí te das cuenta de que
f'
es puro y necesitarías extraer el resultado def
escribir coincidencia. La única forma de 'extraer' un valor monádico es con el>>=
operador, pero dicho operador debe ajustarse inmediatamente después de su uso.Como conclusión: cada vez que termines me gustaría desenvolver completamente esta mónada , solo ríndete. No es el camino correcto
Paso 2 : Intentemos escribir
foldlM
en términos de,foldl
pero primero, usarlo[]
como plegable, ya que es fácil de combinar patrones (es decir, en realidad no necesitamos usarfold
)Ok, eso fue fácil. Vamos a comparar la definición con la
foldl
definición habitual para listas¡¡Frio!! Son más o menos lo mismo. El caso trivial es exactamente lo mismo. El caso recursivo es un poco diferente de bits, desea escribir algo más como:
foldlM' f (f z0 x) xs
. Pero no se compila como en el paso 1, por lo que puede pensar que está bien, no quiero aplicarf
, solo para mantener dicho cálculo y componerlo>>=
. Me gustaría escribir algo más comofoldlM' f (f z0 x >>=) xs
si tuviera sentido ...Paso 3 Date cuenta de que lo que quieres acumular es una composición de funciones y no un resultado. ( Aquí probablemente soy parcial por el hecho de que ya lo sabía porque lo has publicado ).
Por el tipo
initFunc
y el uso de nuestro conocimiento del paso 2 (la definición recursiva) podemos deducir esoinitFunc = return
. La definición def'
se puede completar sabiendo quef'
debe usarf
y>>=
.Como puede ver, no es tan difícil hacerlo. Necesita práctica, pero no soy un desarrollador profesional de haskell y podría hacerlo yo mismo. Es una cuestión de práctica.
fuente
Monad
casos típicos .No necesitas ningún conocimiento específico en matemáticas para escribir una función como
foldM
. Estoy usando Haskell en producción durante 4 años, y también estoy luchando por comprender esta definición defoldM
. Pero eso se debe principalmente a que está mal escrito. Por favor, no lo tome como una falta personal si no puede entender algún código oscuro. Aquí hay una versión más legible defoldlM
Esta función aún no es la más fácil. Principalmente porque tiene un uso no típico de
foldr
donde el acumulador intermedio es una función. Pero puede ver algunos mays que hacen que dicha definición sea más legible:where
(para que conozca la forma de los argumentos).Después de ver dicha función, ahora puede realizar una técnica de razonamiento equitativo para expandir la definición paso a paso y ver cómo funciona. La capacidad de crear tales funciones viene con experiencia. No tengo habilidades matemáticas fuertes, y esta función no es una función típica de Haskell. Pero cuanto más práctica tengas, mejor se pone :)
fuente