2017-01-19 17 views
3

私は無料モナド状態モナドを埋め込むできるようにしようとしています。1つが一致しないと「重複するインスタンス」エラーが表示されるのはなぜですか?

{-# language FlexibleInstances, MultiParamTypeClasses #-} 
module Main where 

import Control.Monad.Free 
import Control.Monad.State 
import Data.Bifunctor 

data Toy state next = 
     Output String next 
    | LiftState (state -> (next, state)) 
    | Done 

instance Functor (Toy s) where 
    fmap f (Output str next) = Output str $ f next 
    fmap f (LiftState stateF) = LiftState (first f . stateF) 
    fmap f Done = Done 

instance MonadState s (Free (Toy s)) where 
    state = overState 

overState :: (s -> (a, s)) -> Free (Toy s) a 
overState = liftF . LiftState 

output :: Show a => a -> Free (Toy s)() 
output x = liftF $ Output (show x)() 

done :: Free (Toy s) r 
done = liftF Done 

program :: Free (Toy Int)() 
program = do 
    start <- get 
    output start 
    modify ((+10) :: (Int -> Int)) 
    end <- get 
    output end 
    done 

interpret :: (Show r) => Free (Toy s) r -> s -> IO() 
interpret (Free (LiftState stateF)) s = let (next, newS) = stateF s 
             in interpret next newS 
interpret (Free (Output str next)) s = print str >> interpret next s 
interpret (Free Done) s = return() 
interpret (Pure x) s = print x 

main :: IO() 
main = interpret program (5 :: Int) 

私はエラーを取得する:ここで私の簡単な試みだ

• Overlapping instances for MonadState Int (Free (Toy Int)) 
    arising from a use of ‘get’ 
    Matching instances: 
    instance [safe] (Functor m, MonadState s m) => 
        MonadState s (Free m) 
     -- Defined in ‘Control.Monad.Free’ 
    instance MonadState s (Free (Toy s)) 
     -- Defined at app/Main.hs:18:10 
• In a stmt of a 'do' block: start <- get 
    In the expression: 
    do { start <- get; 
     output start; 
     modify ((+ 10) :: Int -> Int); 
     end <- get; 
     .... } 
    In an equation for ‘program’: 
     program 
     = do { start <- get; 
       output start; 
       modify ((+ 10) :: Int -> Int); 
       .... } 

私の知る限り収集できるように。このインスタンスを適用しようとしている:

(Functor m, MonadState s m) => MonadState s (Free m) 

free package hereから。しかし、この場合にはFree (Toy s)にマッチしなければならない、それはそれが適用されることを考えて、なぜ私は理解していない必要に応じて何MonadState s (Toy s)はありません。私は私のインスタンス定義を削除した場合

私が手:

他のインスタンスは実際には適用されないというのが私の考えをサポートしてい
• No instance for (MonadState Int (Toy Int)) 
    arising from a use of ‘modify’ 

。指定したインスタンスを使用してこれをコンパイルするにはどうすればよいですか?なぜこれが起こっているのか説明できますか? FlexibleInstancesが使用されていますか?

ありがとうございます!インスタンスを選択する際

+0

メタコメント:確かにこれらの質問はすべて何かの複製でなければなりませんか? –

答えて

4

インスタンスのコンテキスト((Functor m, MonadState s m)ビット)は単に無視されます。これは、コンパイラーが潜在的にコストのかかるバックトラック検索を実行してインスタンスを選択するのを防止するためです。したがって、2つのインスタンスが適用され、1つがインスタンスコンテキストのためにのみ除外される場合、あなたの場合のように、重複します。

これは不幸なMTLの設計の一部、と私はそれぞれのHaskellプログラマは、いくつかのポイントまたは他のに対して、最大ぶつかったと思うものです。修正には多くの選択肢がありません。一般的には、新しいタイプを追加してインスタンスを与えます。

newtype FreeToy s a = FreeToy (Free (Toy s) a) 
instance MonadState s (FreeToy s) where -- ... 
+0

これは素晴らしいことです。どうすれば修正できますか? –

+0

@ChrisPenner多くの選択肢はありません。私は私の答えに少しを追加します。 –

+0

質問の中心は、フリーモナドの中に状態のモナドを埋め込むことです。もし私がそれをきれいにすることができれば、私は幸せです。これを動作させる方法がない場合は、見落としのようですが、あなたは間違いなく、状態モナドを埋め込むことはできません@ChrisPenner –

関連する問題