Confusión sobre el curry y el estilo libre de puntos en Haskell
Pregunta
Estaba intentando implementar la función.
every :: (a -> IO Bool) -> [a] -> IO Bool
cual fue el tema de esta pregunta.Intenté hacer esto sin recursividad explícita.Se me ocurrió el siguiente código
every f xs = liftM (all id) $ sequence $ map f xs
Mi función no funcionó porque no era perezosa (lo cual era requerido en la pregunta), así que no hay votos positivos :-).
Sin embargo, no me detuve ahí.Intenté hacer la función. sin puntos para que fuera más corto (y quizás incluso más fresco).Desde los argumentos f
y xs
son los últimos en la expresión que acabo de soltar:
every = liftM (all id) $ sequence $ map
Pero esto no funcionó como se esperaba, de hecho no funcionó en absoluto:
[1 of 1] Compiling Main ( stk.hs, interpreted ) stk.hs:53:42: Couldn't match expected type `[m a]' against inferred type `(a1 -> b) -> [a1] -> [b]' In the second argument of `($)', namely `map' In the second argument of `($)', namely `sequence $ map' In the expression: liftM (all id) $ sequence $ map Failed, modules loaded: none.
¿Porqué es eso?Tenía la impresión de que era posible simplemente eliminar los argumentos de la función final, que básicamente es de lo que se trata el curry.
Solución
La definición de $ es
f $ x = f x
Vamos plenamente su función de un paréntesis:
every f xs = (liftM (all id)) (sequence ((map f) xs))
y su versión al curry:
every = (liftM (all id)) (sequence map)
Como habrá notado, estos no son idénticos. Sólo se puede caer detrás de argumentos de la función cuando son lo último que se aplica. Por ejemplo,
f x = g c x
es en realidad
f x = (g c) x
y la aplicación de (g c) x ocupa el último lugar, para que pueda escribir
f = g c
Uno de los dibujos con el operador de la aplicación $ es que a menudo se convierte en el operador de composición. en versiones-puntos libres. Esto se debe a
f $ g $ x
es equivalente a
(f . g) $ x
Por ejemplo,
every f xs = liftM (all id) $ sequence $ map f xs
puede convertirse
every f xs = (liftM (all id) . sequence . map f) xs
momento en el que puede caer xs:
every f = liftM (all id) . sequence . map f
Eliminando el argumento f es más difícil, ya que se aplica antes de que el operador de composición. Vamos a usar la definición de puntos de http://www.haskell.org/haskellwiki/Pointfree :
dot = ((.) . (.))
Con los puntos, esto es
(f `dot` g) x = f . g x
y es exactamente lo que tenemos que hacer todos los puntos totalmente libre:
every = (liftM (all id) . sequence) `dot` map
Lamentablemente, debido a las restricciones en el sistema de tipos de Haskell, ésta necesita una firma de tipo explícito:
every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool