在 Monad 实例定义中无法将类型“a”与“b”错误匹配
Couldn't match type ‘a’ with ‘b’error in Monad instance definition
我正在编写一个 haskell 程序来执行一堆语句来修改数据记录。我想在没有用户干预的情况下对每个语句的状态进行修改和测试。我想修改 Control.Monad.Trans.State.Strict 模块以将我的特定类型合并到元组 (,)
中。
在我出现以下错误之前它运行良好
• Couldn't match type ‘a’ with ‘b’
‘a’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b.
StateT s m a -> (a -> StateT s m b) -> StateT s m b
at TestMon.hs:38:7
‘b’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b.
StateT s m a -> (a -> StateT s m b) -> StateT s m b
at TestMon.hs:38:7
Expected type: m (b, s, LogS)
Actual type: m (a, s, LogS)
而且我不明白为什么会出现此错误。
我的代码是这样的:
module TestStateJLJ1 where
import Data.Functor.Identity
import Control.Applicative
import Control.Monad
data LogS = LogOK { stepS:: Int ,logS::[String] }
| LogErr {stepS:: Int , logS::[String] }
deriving (Show)
initLogS = LogOK { stepS=1, logS=[]}
type State s = StateT s Identity
state :: (Monad m) => ((s,LogS) -> (a, s,LogS)) -> StateT s m a
state f = StateT (return . f )
newtype StateT s m a = StateT { runStateT :: (s,LogS) -> m (a,s,LogS) }
instance (Functor m) => Functor (StateT s m) where
fmap f m = StateT $ \ (s,l) ->
fmap (\ (a, s',l') -> (f a, s',l')) $ runStateT m (s,l)
instance (Functor m, Monad m) => Applicative (StateT s m) where
pure a = StateT $ \ (s,l) -> return (a, s,l)
StateT mf <*> StateT mx = StateT $ \ (s,l) -> do
(f, s',l') <- mf (s,l)
(x, s'',l'') <- mx (s',l')
return (f x, s'',l'')
m *> k = m >>= \_ -> k
instance (Monad m) => Monad (StateT s m) where
return a = StateT $ \ (s,l) -> return (a, s,l)
m >>= k = StateT $ \ (s,l) -> do
(a, s',l') <- runStateT m (s,l)
case l' of
LogOK _ _ -> runStateT (k a) (s',l'{stepS=1+stepS l'})
LogErr _ _-> do return ( a, s',l') -- <- This line is causing trouble
fail str = StateT $ \ _ -> fail str
我尝试修改 Monad
实例的行为以测试 LogS
数据类型的值并根据其值:
执行增量stepS
(计算语句的数量)和许多其他事情(尚未实现)并继续执行monad。
或者停止 monad 执行和 return 实际状态。
你知道我的代码有什么问题以及如何改正吗?
您需要从其他 monads 获取一个页面,这些 monads 在 monadic 计算过程中发出错误信号。它们不会 return
错误值,因为这通常是不可能的:m b
类型的单子操作可以 仅 return
类型的值b
,而不是像 (a,s,LogS)
这样的其他任意类型。相反,这些其他错误信号单子使用总和类型来表示错误。例如,monadic 操作 Either MyNastyError b
只能 return
类型 b
的值(通过使用 Right
),但它可以发出类型 MyNastyError
的错误信号使用 Left
.
此外,您通常无法生成 (a,s,LogS)
,因为对类型 a
的了解还不够。它只是某些动作的 return 类型,它在最终失败的动作之前立即绑定到整个 monadic 动作中,因此调用者通常不会准备好对其进行任何操作。不过,您可以 return (s,LogS)
,因为该类型将在给定 monad 中的所有操作中固定。
具体来说,您可以将 StateT
类型重新定义为:
newtype StateT s m a
= StateT { runStateT :: (s, LogS) -> m (Maybe a, s, LogS) }
deriving (Functor)
这使用 Maybe a
表示失败。 returns (Just x, s, l)
可以继续的计算,但是 (Nothing, s, l)
准备停止并转储其状态和日志。
对于这种类型,两个 LogS
构造函数现在是多余的,因为失败已经由 Maybe a
值表示,因此 LogS
可以简化为:
data LogS = LogS { stepS :: Int , logS :: [String] }
deriving (Show)
适当的 Applicative
和 Monad
实例可以更新为:
instance (Monad m) => Applicative (StateT s m) where
pure a = StateT $ \(s, l) -> return (Just a, s, l)
(<*>) = ap
instance (Monad m) => Monad (StateT s m) where
return = pure
m >>= k = StateT $ \(s, l) -> do
(maybeA, s', l') <- runStateT m (s, l)
case maybeA of
Nothing -> return (Nothing, s', l')
Just a -> runStateT (k a) (s', l' {stepS = 1 + stepS l'})
fail err = StateT $ \(s, l) -> return (Nothing, s, l { logS = err:logS l })
请注意,我认为 fail
如果它在这个 monad 中确实 "nice" 失败而不是使用基本 monad 的 fail
更有意义。我在这里假设 logS
字段的顺序相反,因此最新消息附加到头部。
完整代码:
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE DeriveFunctor #-}
module TestStateJLJ1 where
import Data.Functor.Identity
import Control.Monad
data LogS = LogS { stepS :: Int , logS :: [String] }
deriving (Show)
initLogS :: LogS
initLogS = LogS 1 []
newtype StateT s m a
= StateT { runStateT :: (s, LogS) -> m (Maybe a, s, LogS) }
deriving (Functor)
instance (Monad m) => Applicative (StateT s m) where
pure a = StateT $ \(s, l) -> return (Just a, s, l)
(<*>) = ap
instance (Monad m) => Monad (StateT s m) where
return = pure
m >>= k = StateT $ \(s, l) -> do
(maybeA, s', l') <- runStateT m (s, l)
case maybeA of
Nothing -> return (Nothing, s', l')
Just a -> runStateT (k a) (s', l' {stepS = 1 + stepS l'})
fail err = StateT $ \(s, l) -> return (Nothing, s, l { logS = err:logS l })
type State s = StateT s Identity
state :: (Monad m) => ((s, LogS) -> (Maybe a, s, LogS)) -> StateT s m a
state f = StateT $ return . f
我正在编写一个 haskell 程序来执行一堆语句来修改数据记录。我想在没有用户干预的情况下对每个语句的状态进行修改和测试。我想修改 Control.Monad.Trans.State.Strict 模块以将我的特定类型合并到元组 (,)
中。
在我出现以下错误之前它运行良好
• Couldn't match type ‘a’ with ‘b’
‘a’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b.
StateT s m a -> (a -> StateT s m b) -> StateT s m b
at TestMon.hs:38:7
‘b’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b.
StateT s m a -> (a -> StateT s m b) -> StateT s m b
at TestMon.hs:38:7
Expected type: m (b, s, LogS)
Actual type: m (a, s, LogS)
而且我不明白为什么会出现此错误。 我的代码是这样的:
module TestStateJLJ1 where
import Data.Functor.Identity
import Control.Applicative
import Control.Monad
data LogS = LogOK { stepS:: Int ,logS::[String] }
| LogErr {stepS:: Int , logS::[String] }
deriving (Show)
initLogS = LogOK { stepS=1, logS=[]}
type State s = StateT s Identity
state :: (Monad m) => ((s,LogS) -> (a, s,LogS)) -> StateT s m a
state f = StateT (return . f )
newtype StateT s m a = StateT { runStateT :: (s,LogS) -> m (a,s,LogS) }
instance (Functor m) => Functor (StateT s m) where
fmap f m = StateT $ \ (s,l) ->
fmap (\ (a, s',l') -> (f a, s',l')) $ runStateT m (s,l)
instance (Functor m, Monad m) => Applicative (StateT s m) where
pure a = StateT $ \ (s,l) -> return (a, s,l)
StateT mf <*> StateT mx = StateT $ \ (s,l) -> do
(f, s',l') <- mf (s,l)
(x, s'',l'') <- mx (s',l')
return (f x, s'',l'')
m *> k = m >>= \_ -> k
instance (Monad m) => Monad (StateT s m) where
return a = StateT $ \ (s,l) -> return (a, s,l)
m >>= k = StateT $ \ (s,l) -> do
(a, s',l') <- runStateT m (s,l)
case l' of
LogOK _ _ -> runStateT (k a) (s',l'{stepS=1+stepS l'})
LogErr _ _-> do return ( a, s',l') -- <- This line is causing trouble
fail str = StateT $ \ _ -> fail str
我尝试修改 Monad
实例的行为以测试 LogS
数据类型的值并根据其值:
执行增量
stepS
(计算语句的数量)和许多其他事情(尚未实现)并继续执行monad。或者停止 monad 执行和 return 实际状态。
你知道我的代码有什么问题以及如何改正吗?
您需要从其他 monads 获取一个页面,这些 monads 在 monadic 计算过程中发出错误信号。它们不会 return
错误值,因为这通常是不可能的:m b
类型的单子操作可以 仅 return
类型的值b
,而不是像 (a,s,LogS)
这样的其他任意类型。相反,这些其他错误信号单子使用总和类型来表示错误。例如,monadic 操作 Either MyNastyError b
只能 return
类型 b
的值(通过使用 Right
),但它可以发出类型 MyNastyError
的错误信号使用 Left
.
此外,您通常无法生成 (a,s,LogS)
,因为对类型 a
的了解还不够。它只是某些动作的 return 类型,它在最终失败的动作之前立即绑定到整个 monadic 动作中,因此调用者通常不会准备好对其进行任何操作。不过,您可以 return (s,LogS)
,因为该类型将在给定 monad 中的所有操作中固定。
具体来说,您可以将 StateT
类型重新定义为:
newtype StateT s m a
= StateT { runStateT :: (s, LogS) -> m (Maybe a, s, LogS) }
deriving (Functor)
这使用 Maybe a
表示失败。 returns (Just x, s, l)
可以继续的计算,但是 (Nothing, s, l)
准备停止并转储其状态和日志。
对于这种类型,两个 LogS
构造函数现在是多余的,因为失败已经由 Maybe a
值表示,因此 LogS
可以简化为:
data LogS = LogS { stepS :: Int , logS :: [String] }
deriving (Show)
适当的 Applicative
和 Monad
实例可以更新为:
instance (Monad m) => Applicative (StateT s m) where
pure a = StateT $ \(s, l) -> return (Just a, s, l)
(<*>) = ap
instance (Monad m) => Monad (StateT s m) where
return = pure
m >>= k = StateT $ \(s, l) -> do
(maybeA, s', l') <- runStateT m (s, l)
case maybeA of
Nothing -> return (Nothing, s', l')
Just a -> runStateT (k a) (s', l' {stepS = 1 + stepS l'})
fail err = StateT $ \(s, l) -> return (Nothing, s, l { logS = err:logS l })
请注意,我认为 fail
如果它在这个 monad 中确实 "nice" 失败而不是使用基本 monad 的 fail
更有意义。我在这里假设 logS
字段的顺序相反,因此最新消息附加到头部。
完整代码:
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE DeriveFunctor #-}
module TestStateJLJ1 where
import Data.Functor.Identity
import Control.Monad
data LogS = LogS { stepS :: Int , logS :: [String] }
deriving (Show)
initLogS :: LogS
initLogS = LogS 1 []
newtype StateT s m a
= StateT { runStateT :: (s, LogS) -> m (Maybe a, s, LogS) }
deriving (Functor)
instance (Monad m) => Applicative (StateT s m) where
pure a = StateT $ \(s, l) -> return (Just a, s, l)
(<*>) = ap
instance (Monad m) => Monad (StateT s m) where
return = pure
m >>= k = StateT $ \(s, l) -> do
(maybeA, s', l') <- runStateT m (s, l)
case maybeA of
Nothing -> return (Nothing, s', l')
Just a -> runStateT (k a) (s', l' {stepS = 1 + stepS l'})
fail err = StateT $ \(s, l) -> return (Nothing, s, l { logS = err:logS l })
type State s = StateT s Identity
state :: (Monad m) => ((s, LogS) -> (Maybe a, s, LogS)) -> StateT s m a
state f = StateT $ return . f