2010-10-13 10 views
64

W jakich sytuacjach należy używać liftIO? Kiedy używam funkcji ErrorT String IO, funkcjasłuży do podnoszenia działań IO do ErrorT, więc wydaje się zbędna.Haskell: lift vs liftIO

Odpowiedz

75

lift zawsze podnosi się z warstwy "poprzedniej". Jeśli potrzebujesz podnieść z drugiej warstwy, potrzebujesz lift . lift i tak dalej.

Z drugiej strony, liftIO zawsze podnosi się z warstwy IO (która, jeśli jest obecna, znajduje się zawsze na dole stosu). Tak więc, jeśli masz więcej niż 2 warstwy monad, z pewnością docenisz liftIO.

Porównaj typ argumentu w następujących lambdas.

type T = ReaderT Int (WriterT String IO) Bool 

> :t \x -> (lift x :: T) 
\x -> (lift x :: T) :: WriterT String IO Bool -> T 

> :t \x -> (liftIO x :: T) 
\x -> (liftIO x :: T) :: IO Bool -> T 
+26

Generalnie użyję 'liftIO' do podniesienia do warstwy IO, nawet jeśli' lift' jest wystarczający, ponieważ wtedy mogę zmienić stos monad i kod nadal działa. –

+11

@John: dobry punkt. A także sprawia, że ​​oczywiste jest, że podnosisz IO, a nie jakakolwiek inna monada. –

28

liftIO to tylko skrót do IO Monady, w zależności od monady jesteś w zasadzie liftIO równa stosując zmienną liczbę wyciągów . Na początku może to zabrzmieć niepotrzebnie, ale użycie liftIO ma jedną wielką zaletę: sprawia, że ​​twój kod IO jest niezależny od rzeczywistej konstrukcji Monada, dzięki czemu możesz ponownie użyć tego samego kodu bez względu na liczbę warstw, z których zbudowany jest ostatni Monad (jest to dość ważne podczas pisania monad transformatora).

Na wyciągnięcie ręki, liftIO nie przychodzi za darmo, podobnie jak winda: używane transformatory Monada muszą mieć na to wsparcie, np. Monada, w której się znajdujesz, musi być instancją klasy MonadIO, ale większość dzisiejszych Monad (i, oczywiście, sprawdzi to podczas kompilacji: to jest siła Haskella!).