2016-12-07 8 views
2

typeclass없는 모나드로 표기 할 리 바인드 모나드이므로 모나드 동작을 사용할 때마다 MonadDict 모나드 인스턴스 인수 (const 사용)를 무시하지 않아도됩니까?(>> =) 바인딩과 같이 통과 명시 적 사전을 사용하여 모나드에 대한 반환 할 수

+1

은 분명히 더 많은 (>> =) :: MonadDict 분 '같은 것을 원하는 것> mb', 또는 일을 당신이 세 가지를 얻는 경우에 할 계획 다른 사전들? –

+0

@DanielWagner 나는 한 번만 사용한다. 아주 마지막에 사전을 전달하는'usage' 부분을 본다. – coubeatczech

+0

"나는 오직 하나만 건네 준다"같은 보통의 불변 변수는 타입 검사기에게 당신을 확인해달라고하는 좋은 것들이다. 내가 제안한 유형은 그렇게하도록 요청하는 한 가지 방법입니다. –

답변

6

당신은 다음과 같이 수행 할 수 있습니다

{-# 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 
+1

흥미 롭습니다.이 작업은'-XRecordWildCards'로 작동합니다 :'bind ='필드를 각각 호출하면'monadicCode MonadDict {..} = do ...'를 사용할 수 있습니다. 이 중 어떤 것이 좋은 아이디어인지는 확실하지 않지만,이 모든 것이 확실히 흥미 롭습니다. – leftaroundabout

+0

@leftaroundabout 네, 맞습니다. – freestyle

1

짧은 잘못된 대답은 (>>=)에 두 번째 인수의 반환 형식에서 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 aReaderT (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의 구현은 과 동일하지만 MonadDictbind 또는 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 

당신은 독립적으로 기본 mMonad 인스턴스를 장착하고, 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