我编写了一个Haskell类型类,使用 (a -> m _)
形式的类型来声明它的实例会很方便,其中 m
是 (* -> *)
类型,例如monad,而 _
是一个要保持不饱和的槽 . 我知道怎么写 newtype X a m b = X (a -> m b)
,并为 X a m
声明一个实例 . 但我正在寻找的是使用裸露的,未包装的 ->
类型,如果可能的话 .
如果想要为 (a -> _)
形式的类型声明实例,那么你可以写:
instance Foo a ((->) a) where ...
但我不知道如何/是否可以使用 (a -> m _)
形式的类型 . 我想我想在我的实例声明中编写类型构造函数 (->) a _
和类型构造函数 m _
.
我想写这样的东西:
instance Foo a ((->) a (m :: *->*)) where ...
要么:
instance Foo a ((->) a (m *)) where ...
但当然这些都行不通 . 是否有可能做到这一点?
具体来说,这就是我想要实现的目标 . 我为MonadReaders编写了一个类型类,它嵌入在其他MonadReaders的内部(一级),如下所示:
{-# LANGUAGE FunctionalDependencies FlexibleInstances
UndecidableInstances #-}
class MonadReader w m => DeepMonadReader w r m | m -> r where
{ deepask :: m r
; deepask = deepreader id
; deeplocal :: (r -> r) -> m a -> m a
; deepreader :: (r -> a) -> m a
; deepreader f = do { r <- deepask; return (f r) }
}
instance MonadReader r m => DeepMonadReader w r (ReaderT w m) where
{ deepask = lift ask
; deeplocal = mapReaderT . local
; deepreader = lift . reader
}
提供像这样的实例是很好的:
instance MonadReader r m => DeepMonadReader w r ((->) w (m :: * ->
*)) where
{ deepask = \w -> ask
; deeplocal f xx = \w -> local f (xx w)
; deepreader xx = \w -> reader xx
}
1 回答
我认为你走错了路,并且使事情变得比他们需要的复杂得多 .
一些观察:
让我们来探讨你的意思 . 您在
DeepMonadReader
类中使用它作为类型参数m
,因此它需要是monad . 你能给出一个具有这种类型的monad的具体例子吗?为什么不直接使用((->) w)
?w
永远不会出现任何成员签名这一事实表明有些不妥 .我会采取相反的观点 . 谈论monad堆栈是有意义的,monad堆栈是另一个monad堆栈的转换版本 . 例如 . :
对于monad堆栈 m1 到"contain"另一个monad m2 是什么意思?它只是意味着有一种方法可以将 m2 中的计算转换为 m1 中的计算:
当然,使用monad变换器时这只是
lift
.为了表达你在另一个monad中嵌入的monad阅读器的概念,我会使用这个类型类:
这里的想法是一个实例 HasReader m m' r 表达了monad m "contains" monad m' 这个本身就是环境 r 的读者的事实 .
deepAsk 返回 m' 的环境,但作为 m 中的计算 .
deepLocal 使用环境修改函数在 m' 中运行计算,但在 m 中将其作为计算返回 . 请注意这种类型签名与你的签名有何不同:我的 deepLocal 使用不同的monad, m' 和 m 而你的签名只是从 m 到 m .
下一步是决定我们要为 HasReader 编写实例的三元组 (m, m', r) . 很明显,你似乎有这样的例子:
但是想要拥有这些实例似乎也是合理的:
但事实证明,对于任何这些情况我们都不需要 HasReader 类 . 我们可以将表达式编写为 m' 和
lift
中的计算,直到 m .