В каких ситуациях следует использовать liftIO
? Когда я использую ErrorT String IO
, функция lift
работает, чтобы поднять IO-действия в ErrorT
, поэтому liftIO
кажется излишним.
Haskell: подъем против лифта
Ответ 1
lift
всегда поднимается с "предыдущего" слоя. Если вам нужно подняться со второго слоя, вам понадобится lift . lift
и т.д.
С другой стороны, liftIO
всегда поднимается с уровня ввода-вывода (который, если присутствует, всегда находится в нижней части стека). Итак, если у вас более двух слоев монад, вы оцените liftIO
.
Сравните тип аргумента в следующих 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
Ответ 2
liftIO - это всего лишь ярлык для IO Monad, в зависимости от того, в какой Monad вы находитесь. В принципе, liftIO равен использованию переменного количества лифтов. Сначала это может показаться излишним, но использование liftIO имеет одно большое преимущество: он делает ваш код ввода-вывода независимым от реальной конструкции Monad, поэтому вы можете повторно использовать один и тот же код независимо от того, какое количество слоев было создано из вашей последней Monad (это очень важно при записи монадного трансформатора).
В руке ohter liftIO не приходит бесплатно, так как лифт делает: трансформаторы Monad, которые вы используете, должны иметь поддержку для этого, например. Monad, в котором вы находитесь, должен быть экземпляром класса MonadIO, но в настоящее время большинство Monads (и, конечно же, проверка типов проверит это для вас во время компиляции: сила Haskell!).