Haskell : lift 대 liftIO


82

어떤 상황에서 사용해야 liftIO합니까? 내가 사용하는 경우 ErrorT String IOlift기능에 IO 조치를 해제하기 위해 노력하고 ErrorT있으므로, liftIO불필요한 보인다.

답변:


93

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

33
나는 일반적으로 충분 liftIO하더라도 IO 레이어로 들어 올리는 데 사용할 것입니다 lift. 왜냐하면 모나드 스택을 변경할 수 있고 코드는 여전히 작동하기 때문입니다.
John L

14
@John : 좋은 지적입니다. 또한 다른 모나드가 아닌 IO를 해제하고 있음을 분명히합니다.
Roman Cheplyaka

나는 초보자입니다. lift이 답변 (및 질문)은에서 온 것으로 가정합니다 Control.Monad.Trans.Class. 아니 Monadic lifting또는 첫 번째 섹션에 설명 된대로 일반 리프팅 여기 ?
Nawaz

37

liftIO는 IO Monad에 대한 바로 가기 일뿐입니다. 어떤 Monad에 있든 기본적으로 liftIO는 다양한 수의 리프트를 사용하는 것과 같습니다. 처음에는 중복 된 것처럼 들릴 수 있지만 liftIO를 사용하면 한 가지 큰 장점이 있습니다. IO 코드가 실제 Monad 구성에 종속되지 않으므로 최종 Monad가 빌드 된 레이어 수에 관계없이 동일한 코드를 재사용 할 수 있습니다 (이것은 매우 중요합니다 모나드 변환기를 작성할 때).

다른 한편으로, liftIO는 리프트처럼 무료로 제공되지 않습니다. 사용중인 Monad 변환기는이를 지원해야합니다. (물론 타입-체커는 컴파일 타임에 이것을 체크 할 것입니다 : 이것이 Haskell의 강점입니다!).


1

이전 답변은 모두 차이점을 잘 설명합니다. 나는 단지 내부 작동에 대해 약간의 빛을 비추고 싶었다. 그래서 그것이 어떻게 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괜찮다면 기본적으로 이유 입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.