어떤 상황에서 사용해야 liftIO
합니까? 내가 사용하는 경우 ErrorT String IO
는 lift
기능에 IO 조치를 해제하기 위해 노력하고 ErrorT
있으므로, liftIO
불필요한 보인다.
답변:
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
liftIO는 IO Monad에 대한 바로 가기 일뿐입니다. 어떤 Monad에 있든 기본적으로 liftIO는 다양한 수의 리프트를 사용하는 것과 같습니다. 처음에는 중복 된 것처럼 들릴 수 있지만 liftIO를 사용하면 한 가지 큰 장점이 있습니다. IO 코드가 실제 Monad 구성에 종속되지 않으므로 최종 Monad가 빌드 된 레이어 수에 관계없이 동일한 코드를 재사용 할 수 있습니다 (이것은 매우 중요합니다 모나드 변환기를 작성할 때).
다른 한편으로, liftIO는 리프트처럼 무료로 제공되지 않습니다. 사용중인 Monad 변환기는이를 지원해야합니다. (물론 타입-체커는 컴파일 타임에 이것을 체크 할 것입니다 : 이것이 Haskell의 강점입니다!).
이전 답변은 모두 차이점을 잘 설명합니다. 나는 단지 내부 작동에 대해 약간의 빛을 비추고 싶었다. 그래서 그것이 어떻게 liftIO
마 법적이지 않은지 이해하는 것이 더 쉬울 수 있었다 .
liftIO :: IO a -> m a
현명한 도구입니다.
lift :: (Control.Monad.Trans.Class.MonadTrans t, Monad m) => m a -> t m a
그리고 가장 자주 바닥 모나드가있을 때 사용 IO
. 를 들어 IO
모나드 그것의 정의는 매우 간단합니다.
class (Monad m) => MonadIO m where
liftIO :: IO a -> m a
instance MonadIO IO where
liftIO = id
그 간단한 ... liftIO
사실 모나드 만을 id
위한 IO
것이며 기본적으로 IO
유형 클래스의 정의에 포함되는 유일한 것입니다.
문제는 여러 계층의 모나드 변환기로 구성된 모나드 유형이있을 때 해당 모나드 변환기 계층 각각에 IO
대한 MonadIO
인스턴스를 갖는 것이 좋습니다 . 예를 들어, MonadIO
인스턴스가 MaybeT m
필요 m
로 할 MonadIO
뿐만 아니라 typeclass.
MonadIO
인스턴스 작성 은 기본적으로 매우 간단한 작업입니다. 들어 MaybeT m
그것은 다음과 같이 정의된다
instance (MonadIO m) => MonadIO (MaybeT m) where
liftIO = lift . liftIO
또는 StateT s m
instance (MonadIO m) => MonadIO (StateT s m) where
liftIO = lift . liftIO
그들은 모두 동일합니다. 당신이 당신에게 할 수있는 하나의 필요성 4 층 변압기 스택이있을 때 상상 lift . lift . lift . lift $ myIOAction
하거나를 liftIO myIOAction
. 당신이 그것에 대해 생각한다면, 모든 lift . liftIO
것이 당신을 스택에서 한 층 아래로 내려 가게 될 것입니다. 그것이 정의 된 IO
곳 까지 파고 liftIO
들어 위의 id
구성된 lift
s 와 같은 동일한 코드로 마무리 될 것입니다 .
따라서 이것이 기본적으로 변압기 스택 구성에 관계없이 모든 언더 레이 레이어가 구성원 MonadIO
이고 MonadTrans
단일 레이어가 liftIO
괜찮다면 기본적으로 이유 입니다.
liftIO
하더라도 IO 레이어로 들어 올리는 데 사용할 것입니다lift
. 왜냐하면 모나드 스택을 변경할 수 있고 코드는 여전히 작동하기 때문입니다.