2012-03-17 14 views
10

Estoy ayudando a un amigo a aprender Haskell y recientemente creó un código como este, que revisa y produce un bucle de grabación de CPU en tiempo de ejecución. Estoy completamente desconcertado por esto.¿Por qué la importación de Control.Applicative permite que este código incorrecto escriba check?

import Control.Monad 
import Control.Applicative 

main = forever putStrLn "Hello, infinity" 

Eso no debería escribir, pero sí. La versión correcta sería claramente:

main = forever $ putStrLn "Hello, infinity" 

Lo raro y sorprendente para mí es que se obtienen diferentes resultados con y sin importar Control.Applicative. Sin importar que, no tipo de comprobación:

Prelude Control.Monad> forever putStrLn "Hello, infinity" 

<interactive>:1:1: 
    No instance for (Monad ((->) String)) 
     arising from a use of `forever' 
    Possible fix: add an instance declaration for (Monad ((->) String)) 
    In the expression: forever putStrLn "Hello, infinity" 
    In an equation for `it': it = forever putStrLn "Hello, infinity" 

no veo una instancia de Monad para ((->) String en la fuente para Control.Applicative, así que supongo que está ocurriendo algo raro debido a su uso de Control.Category o Control.Arrow, pero no sé. Así que supongo que tengo dos preguntas:

  1. ¿Qué pasa con la importación de Control.Applicative que permite que esto suceda?
  2. ¿Qué sucede cuando ingresa al bucle infinito? ¿Qué está tratando de ejecutar Haskell en ese caso?

Gracias,

Respuesta

13

No hay una instancia para (->) String, pero hay una instancia para (->) e ... y esa instancia es muy, muy útil en muchas situaciones. Para la segunda pregunta, hay que echar un vistazo a forever y la instancia de clase de funciones:

instance Monad ((->) e) where 
    return x = \e -> x 
    m >>= f = \e -> f (m e) e 

forever m = m >> forever m = m >>= \_ -> forever m 

Ahora bien, ¿qué forever putStrLn hacer?

forever putStrLn 
    = putStrLn >>= \_ -> forever putStrLn 
    = \e -> (\_ -> forever putStrLn) (putStrLn e) e 
    = \e -> (forever putStrLn) e 
    = forever putStrLn 

... Es sólo un bucle infinito puro, básicamente idéntica a loop = loop.

para conseguir algo de intuición para lo que está pasando con la mónada lector (como se le conoce), echar un vistazo a the documentation, el todo sobre Mónadas section on Reader, y hay algunos indicios salpicadas a lo largo del Typeclassopedia lo que podría ayudar.

+0

¿Puede explicar en qué es útil la instancia de '(->) e'? –

+4

@DanielLyons Es útil cuando tiene muchas funciones que necesitan acceso a información de configuración compartida. Luego puede escribir (por ejemplo) 'foo >> = bar >> = baz' en lugar de repetir el entorno en todas partes como en' \ e -> let x = foo e; y = barra x e; z = baz y e en y'. –

6

Control.Applicative importa Control.Monad.Instances, y por lo tanto reexporta las instancias de Control.Monad.Instances. Esto incluye Functor y Monad instancias para ((->) r).

Cuestiones relacionadas