22 votos

¿Plegable, función composición, mónadas y pereza, ¡ oh mi?

Estoy perplejo. Puedo escribir esto:

import Control.Monad

main = print $ head $ (foldr (.) id [f, g]) [3]
  where f = (1:)
        g = undefined

y el resultado es 1. Eso tiene sentido, porque se reduce a:

main = print $ head $ ((1:) . undefined . id) [3]
main = print $ head $ (1:) ((undefined . id) [3])
main = print $ head $ 1 : ((undefined . id) [3])
main = print $ 1

Pero si yo uso una vagamente similar monádico técnica, no funciona de la misma:

import Control.Monad

main = print $ (foldr (<=<) return [f, g]) 3
  where f = const Nothing
        g = undefined

Esto golpea prelude.Undefined. Lo cual es extraño, porque yo esperaría a reducir:

main = print $ ((const Nothing) <=< undefined <=< return) 3
main = print $ return 3 >>= undefined >>= (\_ -> Nothing)
main = print $ Nothing -- nope! instead, undefined makes this blow up

Sin embargo, cambiando el orden de composición:

import Control.Monad

main = print $ (foldr (>=>) return [f, g]) 3
  where f = const Nothing
        g = undefined

hace cumplir la espera cortocircuito y produce Nothing.

main = print $ (const Nothing >=> undefined >=> return) 3
main = print $ (const Nothing 3) >>= undefined >>= return
main = print $ Nothing >>= undefined >>= return
main = print $ Nothing

Supongo que la comparación de los dos enfoques podría haber sido comparar manzanas y naranjas, pero ¿puede explicar la diferencia? Pensé que f <=< g fue el monádico analógica a la f . g, pero que, al parecer, no como análoga como yo pensaba. Puede usted explicar por qué?

20voto

hammar Puntos 89293

Depende de en qué monada el que está trabajando, y cómo su (>>=) operador está definido.

En el caso de Maybe, (>>=) es estricta en su primer argumento, como Daniel Fischer explicó.

Aquí están algunos de los resultados de un puñado de otras mónadas.

> :set -XNoMonomorphismRestriction
> let foo = (const (return 42) <=< undefined <=< return) 3
> :t foo
foo :: (Num t, Monad m) => m t

Identidad: Perezoso.

> Control.Monad.Identity.runIdentity foo
42

IO: Estricta.

> foo :: IO Integer
*** Exception: Prelude.undefined

Lector: Perezoso.

> Control.Monad.Reader.runReader foo "bar"
42

Escritor: Tiene un perezoso y un estricto variante.

> Control.Monad.Writer.runWriter foo
(42,())
> Control.Monad.Writer.Strict.runWriter foo
*** Exception: Prelude.undefined

Estado: Tiene también una estricta y un perezoso versión.

> Control.Monad.State.runState foo "bar"
(42,"*** Exception: Prelude.undefined
> Control.Monad.State.Strict.runState foo "bar"
*** Exception: Prelude.undefined

Cont: Estricta.

> Control.Monad.Cont.runCont foo id
*** Exception: Prelude.undefined

19voto

Daniel Fischer Puntos 114146

El enlace para Maybe es estricto en el primer argumento.

Just v >>= f = f v
Nothing >>= f = Nothing

Así que cuando se trate de

Just v >>= undefined >>= \_ -> Nothing

usted golpea

undefined v >>= \_ -> Nothing

y la aplicación necesita para averiguar si undefined v es Nothing o Just something a ver que la ecuación de (>>=) de uso.

Por otro lado,

Nothing >>= undefined

determina el resultado, sin mirar el segundo argumento de (>>=).

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X