2016-05-11 2 views
1
data InterpreterM a = ExeInterpreter a | PropInterpreter a 

newtype InterpreterMT m a = InterpreterMT { runInterpreterMT :: m (InterpreterM a) } 

instance (Monad m) => Monad (InterpreterMT m) where 
    return x = lift . return 
    x >>= f = InterpreterMT $ do 
     m <- runInterpreterMT x 
     case m of 
      (ExeInterpreter a) -> runInterpreterMT (f a) 

instance MonadTrans InterpreterMT where 
    lift m = lift . (ExeInterpreter m) 

を持ち上げ、私はエラーを持っている、と私は理由を知りません:あなたはいけない自分のモナド変圧器と

Interpreter.hs:25:20: 
    Couldn't match expected type `InterpreterMT m a' 
       with actual type `a2 -> t1 m1 a2' 
    In the expression: lift . return 
    In an equation for `return': return x = lift . return 
    In the instance declaration for `Monad (InterpreterMT m)' 

Interpreter.hs:32:18: 
    Couldn't match expected type `InterpreterMT m a' 
       with actual type `a0 -> t0 m0 a1' 
    In the expression: lift . (ExeInterpreter m) 
    In an equation for `lift': lift m = lift . (ExeInterpreter m) 
    In the instance declaration for `MonadTrans InterpreterMT' 

Interpreter.hs:32:27: 
    Couldn't match expected type `a0 -> m0 a1' 
       with actual type `InterpreterM (m a)' 
    In the return type of a call of `ExeInterpreter' 
    Probable cause: `ExeInterpreter' is applied to too many arguments 
    In the second argument of `(.)', namely `(ExeInterpreter m)' 
    In the expression: lift . (ExeInterpreter m) 

答えて

5

ようにする必要があり何ニコラスは述べています。私はポイントフリーのスタイルを使用しなかったので、タイプを理解するのが少し簡単かもしれません。あなたは、変圧器のためのより良い感覚を得るために実装例に見ることができます - Control.Monad.Trans.Class

data InterpreterM a = ExeInterpreter a 
        | PropInterpreter a 

newtype InterpreterMT m a = InterpreterMT { runInterpreterMT :: m (InterpreterM a) } 

instance (Monad m) => Monad (InterpreterMT m) where 

-- return :: Monad m => a -> InterpreterMT m a 
    return x = InterpreterMT $ (return . ExeInterpreter) x 

-- or after you defined MonadTrans below 
-- return x = lift . return $ x 

-- (>>=) :: Monad m => InterpreterMT m a -> (a -> InterpreterMT m b) -> InterpreterMT m b 
    (>>=) ima f = InterpreterMT $ do 
     ia <- runInterpreterMT ima 
     case ia of 
      (ExeInterpreter a) -> runInterpreterMT $ f a 
      (PropInterpreter a) -> runInterpreterMT $ f a 

instance MonadTrans InterpreterMT where 

-- lift :: Monad m => m a -> InterpreterMT m a 
    lift ma = InterpreterMT $ (return . ExeInterpreter) =<< ma 
+0

私は、これは 'InterpreterMT(リターン(PropInterpreter A))>> = return' =' InterpreterMT(リターン(ExeInterpreter A))ことを必要と考えます'違反するx >> = return = x' – Michael

+0

あなたはまったく正しいです。これは簡略化されたEitherTの定義ですが、重要な違いは、Typeパラメータが1つしかなく、Eitherのように2つではないことです。 '(PropInterpreter a)return(PropInterpreter a)'のようにcase式を変更する必要がありますが、 'InterpreterMT m a'で指定された' InterpreterMT m b'と一致しないので、型チェッカーはエラーを投げます。残念ながら私はこれに対する解決策を知らない。 – Cirquit

+1

そうですね、どちらの場合も、 'a'に' f'を適用してから、再び一致して結果を組み立てるべきです。この回答は、[彼の他の質問](http://stackoverflow.com/questions/37187933/lift-monad-reader-local/37190716#37190716)私はちょうどInterpreterMTを(ある種の)Monoid + WriterTに還元する答えはあまりにも複雑で実用的ではありません。私は正しいモナドインスタンスが効果的に(m、)/ WriterT m – Michael

4

liftが存在しないので、文脈にMonadTransの任意のインスタンスを持っているようです。

さらに重要なことに、機能の種類を見てください。 xはタイプaの値であり、return xはタイプ(InterpreterMT m) aのエレメントを指定する必要があります。あなたがデータコンストラクタInterpreterMTを使用して、それをリターンの体を意味m (InterpreterM a)

を与える必要があり、このために

return . PropInterpreter $ x 
関連する問題