2011-12-19 10 views
5

Po haskell tutorial, autor udostępnia następujące realizację withFile metoda:Jak withFile jest realizowany w Haskell

withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a 
withFile' path mode f = do 
    handle <- openFile path mode 
    result <- f handle 
    hClose handle 
    return result 

Ale dlaczego musimy owinąć result w return? Czy dostarczona funkcja nie powoduje już zwrócenia wartości IO według typu Handle -> IO a?

Odpowiedz

7

Masz rację: f już zwraca IO, więc jeśli funkcja zostały napisane tak:

withFile' path mode f = do 
    handle <- openFile path mode 
    f handle 

nie byłoby potrzeba powrotu. Problemem jest hClose handle pochodzi pomiędzy, więc musimy zapisać wynik pierwszy:

result <- f handle 

i robi <- pozbywa się IO. Tak więc return odkłada go.

+0

Oh d'oh! Zupełnie brakowało operatora "ssania" '<-'! – drozzy

+1

Czy może to być również 'niech result = f uchwyt; hZamknij uchwyt; wynik "czy też znowu nie rozumiem monady? – delnan

+3

@delnan to 'do {handle <- ścieżka trybu openFile; hZamknij uchwyt; f uchwyt; } ', więc' f uchwyt 'prawdopodobnie narzekałby na zamknięty uchwyt. –

3

To jedna z trudnych drobiazgów, które mnie zdezorientowały, kiedy po raz pierwszy spróbowałem Haskella. Nie rozumiesz znaczenia konstrukcji <- w notacji do-notacji. result <- f handle nie oznacza "przypisanie wartości f handle do result"; oznacza to "wiążę result z wartością" wyodrębnioną "z monadycznej wartości f handle" (gdzie "ekstrakcja" dzieje się w jakiś sposób, który jest określony przez konkretną instancję Monady, której używasz, w tym przypadku monotonię IO).

Tj jakiegoś Monad typeclass m, oświadczenie <- bierze wyrażenie typu m a na prawej stronie i zmienną typu a na lewej stronie, i wiąże zmienną na wartość. Tak więc w twoim konkretnym przykładzie, z result <- f handle, mamy typy f result :: IO a, result :: a i return result :: IO a.

PS do-notation ma również specjalną formę let (bez słowa kluczowego in w tym przypadku!), Która działa jako czysty odpowiednik <-. Więc można było przepisać swój przykład jako:

withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a 
withFile' path mode f = do 
    handle <- openFile path mode 
    let result = f handle 
    hClose handle 
    result 

W tym przypadku, ponieważ let to proste zadanie, rodzaj result jest IO a.

+1

Fajnie! Ja nazywam '<-' operatorem ssania, ponieważ wysysa wartość z rhs :-) – drozzy

Powiązane problemy