typeclass없는 모나드로 표기 할 리 바인드 모나드이므로 모나드 동작을 사용할 때마다 MonadDict
모나드 인스턴스 인수 (const
사용)를 무시하지 않아도됩니까?(>> =) 바인딩과 같이 통과 명시 적 사전을 사용하여 모나드에 대한 반환 할 수
답변
당신은 다음과 같이 수행 할 수 있습니다
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE RecordWildCards #-}
module Lib where
import Prelude hiding(return, fail, (>>=), (>>))
data MonadDict m = MonadDict
{ (>>=) :: forall a b. m a -> (a -> m b) -> m b
, (>>) :: forall a b. m a -> m b -> m b
, return :: forall a. a -> m a
, fail :: forall a. String -> m a
}
monadDictIO :: MonadDict IO
monadDictIO = ...
foo :: MonadDict m -> String -> m()
foo = ...
usage = let
monadicCode [email protected]{..} = do
ln <- getLine
putStrLn ln
foo m ln
in monadicCode monadDictIO
흥미 롭습니다.이 작업은'-XRecordWildCards'로 작동합니다 :'bind ='필드를 각각 호출하면'monadicCode MonadDict {..} = do ...'를 사용할 수 있습니다. 이 중 어떤 것이 좋은 아이디어인지는 확실하지 않지만,이 모든 것이 확실히 흥미 롭습니다. – leftaroundabout
@leftaroundabout 네, 맞습니다. – freestyle
짧은 잘못된 대답은 (>>=)
에 두 번째 인수의 반환 형식에서 MonadDict m
인수를 삭제할 수 있습니다 :
(>>=) :: (MonadDict m -> m a) -> (a -> m b) -> (MonadDict m -> m b)
을하지만 그건하지 않습니다 정말 모든 구문 문제를 해결합니다. 다른 사람이 유형이 Monad m => a -> m b
인 기존의 화살표가있는 경우 명시적인 사전 전달은 a -> (MonadDict m -> m b)
유형이며 (>>=)
의 두 번째 인수로 사용할 수 없습니다. 두 번째 인수와 호환되도록 함수 drop :: (MonadDict m -> m b) -> m b
이있는 경우 MonadDict
을 전달할 이유가 없습니다.
당신은 MonadDict m
을 읽을 수있는 ReaderT
변압기를 개혁하고 있습니다.
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
당신이이 m a
ReaderT (MonadDict m) m a
로를 보내고 lift
의 상당의 const
를 사용 할 때마다. 귀하의 예제는 const
대신 lift
으로 작성하면 익숙하지 않게 보입니다. 여기
usage = let
monadicCode = do
ln <- lift getLine
lift . putStrLn $ ln
in monadicCode monadDictIO
는
ReaderT
를 사용하여 완벽한 예입니다;
ReaderT (MonadDict m) m
에 대해 새 유형을 만들고
lift
에 다른 이름을 지정하는 것이 좋습니다.
(>>=)
및
return
의 구현은 과 동일하지만
MonadDict
의
bind
또는
ret
을 사용합니다. 당신이 그것을 자신의 유형을주는 경우에
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RebindableSyntax #-}
module Lib
(usage
) where
import Prelude hiding ((>>=), return)
import qualified Prelude as P ((>>=), return)
import Control.Monad.Trans.Reader
data MonadDict m = MonadDict {
bind :: forall a b. m a -> (a -> m b) -> m b ,
ret :: forall a. a -> m a }
type ReadM m a = ReaderT (MonadDict m) m a
(>>=) :: ReadM m a -> (a -> ReadM m b) -> ReadM m b
m >>= k = ReaderT $ \[email protected] { bind = bind } -> bind (runReaderT m d) (\a -> runReaderT (k a) d)
return :: a -> ReadM m a
return a = ReaderT $ \[email protected] { ret = ret } -> ret a
lift :: m a -> ReadM m a
lift m = ReaderT $ \_ -> m
monadDict :: Monad m => MonadDict m
monadDict = MonadDict {
bind = (P.>>=),
ret = P.return
}
example1 :: String -> ReadM IO()
example1 a = do
lift . putStrLn $ a
lift . putStrLn $ a
example2 :: ReadM IO()
example2 = do
example1 "Hello"
ln <- lift getLine
lift . putStrLn $ ln
usage :: IO()
usage = runReaderT example2 monadDict
당신은 독립적으로 기본 m
의 Monad
인스턴스를 장착하고, RebindableSyntax
생략 할 수 있습니다. (-> 메가 A) - -> 석사 ->
newtype ReadMD m a = ReadMD {runReadMD :: MonadDict m -> m a}
instance Functor (ReadMD f) where
fmap = liftM
instance Applicative (ReadMD f) where
pure = return
(<*>) = ap
instance Monad (ReadMD m) where
m >>= k = ReadMD $ \[email protected] { bind = bind } -> bind (runReadMD m d) (\a -> runReadMD (k a) d)
return a = ReadMD $ \[email protected] { ret = ret } -> ret a
은 분명히 더 많은 (>> =) :: MonadDict 분 '같은 것을 원하는 것> mb', 또는 일을 당신이 세 가지를 얻는 경우에 할 계획 다른 사전들? –
@DanielWagner 나는 한 번만 사용한다. 아주 마지막에 사전을 전달하는'usage' 부분을 본다. – coubeatczech
"나는 오직 하나만 건네 준다"같은 보통의 불변 변수는 타입 검사기에게 당신을 확인해달라고하는 좋은 것들이다. 내가 제안한 유형은 그렇게하도록 요청하는 한 가지 방법입니다. –