it-swarm.com.ru

Haskell: лифт против лифта

В каких ситуациях следует использовать liftIO? Когда я использую ErrorT String IO, функция lift работает для поднятия действий IO в ErrorT, поэтому liftIO кажется излишним.

74
Lachlan

lift всегда поднимается из "предыдущего" слоя. Если вам нужно подняться со второго слоя, вам потребуется lift . lift и так далее.

С другой стороны, liftIO всегда поднимается со слоя IO (который, когда присутствует, всегда находится внизу стека). Итак, если у вас более 2-х слоев монад, вы оцените liftIO.

Сравните тип аргумента в следующих лямбдах:

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
84
Roman Cheplyaka

liftIO - это просто ярлык для монады IO, в какой бы монаде вы ни находились. По сути, liftIO равняется использованию переменного числа лифтов. Поначалу это может показаться излишним, но использование liftIO имеет одно большое преимущество: это делает ваш код IO независимым от фактической конструкции Monad, поэтому вы можете повторно использовать один и тот же код, независимо от того, какой слой был построен в вашей последней монаде. из (это очень важно при написании монадного преобразователя).

С другой стороны, liftIO не приходит бесплатно, как делает лифт: используемые вами трансформаторы Monad должны иметь поддержку, например, Monad, в котором вы находитесь, должен быть экземпляром класса MonadIO, но большинство Monads в настоящее время делают это (и, конечно, средство проверки типов проверит это для вас во время компиляции: в этом сила Haskell!).

31
Cristiano Paris