[haskell] Haskell : lift 대 liftIO

어떤 상황에서 사용해야 liftIO합니까? 내가 사용하는 경우 ErrorT String IOlift기능에 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구성된 lifts 와 같은 동일한 코드로 마무리 될 것입니다 .

따라서 이것이 기본적으로 변압기 스택 구성에 관계없이 모든 언더 레이 레이어가 구성원 MonadIO이고 MonadTrans단일 레이어가 liftIO괜찮다면 기본적으로 이유 입니다.


답변