2012-03-17 10 views
10

Sto aiutando un amico a imparare Haskell e di recente ha creato un codice come questo, che controlla e genera un ciclo di masterizzazione della CPU in fase di runtime. Sono completamente sconcertato da questo.Perché l'importazione di Control.Applicative consente a questo codice errato di digitare il controllo?

import Control.Monad 
import Control.Applicative 

main = forever putStrLn "Hello, infinity" 

che non deve digitare controllare, ma lo fa. La versione corretta sarebbe chiaramente:

main = forever $ putStrLn "Hello, infinity" 

Cosa c'è di strano e sorprendente per me è che si ottengono risultati diversi con e senza l'importazione Control.Applicative. Senza l'importazione, non tipo si verifica:

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" 

non vedo un'istanza Monade per ((->) String nel sorgente per Control.Applicative, quindi sto cercando di indovinare qualcosa di strano sta accadendo a causa del suo uso di Control.Category o Control.Arrow, ma non lo so. Quindi credo che ho due domande:

  1. Che cosa è circa l'importazione di Control.Applicative che lascia che questo accada?
  2. Cosa succede quando entra nel ciclo infinito? Che cosa sta cercando di eseguire Haskell in questo caso?

Grazie,

risposta

13

Non c'è un'istanza per (->) String, ma c'è un'istanza per (->) e ... e questo esempio è molto, molto utile in molte situazioni. Per la seconda domanda, dobbiamo dare un'occhiata al forever e l'istanza di classe per le funzioni:

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

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

Ora, che cosa forever putStrLn fare?

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

... E 'solo un loop infinito puro, sostanzialmente identico a loop = loop.

per ottenere qualche intuizione di ciò che sta succedendo con la monade lettore (come è noto), date un'occhiata al the documentation, l'All About Monadi section on Reader, e ci sono alcuni suggerimenti sparsi in tutta la Typeclassopedia che potrebbe aiutare.

+0

Puoi approfondire su cosa è utile l'istanza per '(->) e'? –

+4

@DanielLyons È utile quando si hanno molte funzioni che hanno tutte bisogno di accedere ad alcune informazioni di configurazione condivise. Quindi puoi scrivere (ad esempio) 'foo >> = bar >> = baz' invece di ripetere l'ambiente ovunque come in' \ e -> lascia x = foo e; y = bar x e; z = baz y e in y'. –

6

Control.Applicative importazioni Control.Monad.Instances e pertanto riesporta le istanze da . Ciò include le istanze Functor e Monad per ((->) r).

Problemi correlati