我有monad变换器堆栈的类型别名:
type KStat s a = ReaderT (KStatRoot s) (ExceptT KindError (ST s)) a
我需要将用户从这种类型中抽象出来,主要是因为KStatRoot
结构导致了循环依赖。因此,我创建了一个单独的模块并为其定义了类型类:
class (Monad (m s), MonadError KindError (m s)) =>
MStat m s where
liftToST :: ST s a -> m s a
kstatNewRef :: a -> m s (STRef s a)
kstatReadRef :: STRef s a -> m s a
kstatWriteRef :: STRef s a -> a -> m s ()
这个定义编译正常(尽管需要{-# LANGUAGE MultiParamTypeClasses,FlexibleContexts #-}
才能工作,但我可以看到为什么这两个都是必需的),并且我已经能够将一些使用网站转换为类型类并让它们输入检查,所以一切似乎都没问题。但我正在努力研究如何为类定义我的实例:
instance MStat (KStat s a) s where
liftToST = lift . lift
kstatNewRef = liftToST . newSTRef
kstatReadRef = liftToST . readSTRef
kstatWriteRef r v = liftToST $ writeSTRef r v
给我错误:
src/KindLang/Data/KStat.hs:27:17:
The first argument of ‘MStat’ should have kind ‘* -> * -> *’,
but ‘KStat s a’ has kind ‘*’
In the instance declaration for ‘MStat (KStat s a) s’
哪种有意义,但如果我在实例标题中将KStat s a
更改为KStat
,则会出现此错误:
src/KindLang/Data/KStat.hs:27:10:
Type synonym ‘KStat’ should have 2 arguments, but has been given none
In the instance declaration for ‘MStat KStat s’
似乎基本上说的恰恰相反。
我在模块中使用这些语言扩展我声明了实例:
{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses #-}
如何解决这些错误?
演示错误的完整文件如下:
{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleContexts,
FlexibleInstances, MultiParamTypeClasses #-}
import Control.Monad.Except
import Control.Monad.ST
import Control.Monad.Reader
import Data.STRef
data KStatRoot s = KStatRoot
data KindError
class (Monad (m s), MonadError KindError (m s)) =>
MStat m s where
liftToST :: ST s a -> m s a
kstatNewRef :: a -> m s (STRef s a)
kstatReadRef :: STRef s a -> m s a
kstatWriteRef :: STRef s a -> a -> m s ()
type KStat s a = ReaderT (KStatRoot s) (ExceptT KindError (ST s)) a
instance MStat (KStat s m) s where
liftToST = lift . lift
kstatNewRef = liftToST . newSTRef
kstatReadRef = liftToST . readSTRef
kstatWriteRef r v = liftToST $ writeSTRef r v
答案 0 :(得分:4)
第一个错误是“正确”(您需要在实例声明中使用两种类型的参数),并且您尝试的修复是有意义的。
但是,如果没有参数,type
同义词就不存在。也就是说,
type Foo a = ...
您不能单独使用Foo
。必须将Foo
应用于参数才能由类型检查器处理。这是导致第二次错误的原因。
我看到的唯一解决方法是将KStat
更改为newtype
:
newtype KStat s a = KStat{ runKStat :: ReaderT (KStatRoot s) (ExceptT KindError (ST s)) a }
这将允许您在没有参数的情况下使用KStat
。您只需在任何地方添加明确的runKStat
/ KStat
转化。