Haskell 为什么我会得到';重叠实例';不使用时出错';不匹配?

Haskell 为什么我会得到';重叠实例';不使用时出错';不匹配?,haskell,state-monad,free-monad,Haskell,State Monad,Free Monad,我试图允许在我的自由单子中嵌入一个状态单子;以下是我的简单尝试: {-# 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 (

我试图允许在我的自由单子中嵌入一个状态单子;以下是我的简单尝试:

{-# 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)
从 ; 然而,在这种情况下,它必须匹配
免费(玩具s)
,并且没有
MonadState s(玩具s)
,所以我不理解为什么它认为它适用

如果删除实例定义,则会得到:

• No instance for (MonadState Int (Toy Int))
    arising from a use of ‘modify’
这支持了我的想法,即另一个实例实际上并不适用;如何使用我指定的实例来编译它?你能解释一下为什么会发生这种情况吗?是否由于使用了
FlexibleInstances

谢谢

在选择实例时,实例上下文(函子m,MonadState s m)位被忽略。这是为了防止编译器在选择实例时必须进行可能代价高昂的回溯搜索。因此,如果两个实例适用,而一个仅因实例上下文而被排除,就像在您的案例中一样,这是一个重叠

这是mtl设计中一个不幸的部分,我认为每个Haskell程序员在某个时候都遇到过这个问题。修复的选择不多;通常,添加一个新类型并给出实例,如中所示

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

很高兴知道这一点;“但我该怎么解决呢?”克里斯彭纳说,选择不多。我想补充一点我的答案。问题的核心是我想在我的免费单子中嵌入状态单子;因此,如果我能干净利落地做到这一点,那么我很高兴;虽然这看起来有点疏忽,如果没有办法让它工作@ChrisPenner你绝对不能嵌入状态monad并使用
MonadState
——MonadState上的fundep说任何给定的monad只能有一种状态。这对于减少使用类方法时所需的类型注释数量非常重要。如果我将类型反参数化为仅
Toy
,并将其限制为
Int
,作为状态,则MonadState应该能够唯一地确定
Toy->Int
;对吗?我仍然很难相信你不能将mtl操作嵌入到免费软件中;似乎是一个非常有用的案例!其他人如何在他们的免费单子和DSL中进行状态描述?新类型的版本看起来还不错,所以我会试试看!Meta评论:这些问题肯定都是重复的吗?
• No instance for (MonadState Int (Toy Int))
    arising from a use of ‘modify’
newtype FreeToy s a = FreeToy (Free (Toy s) a)
instance MonadState s (FreeToy s) where -- ...