[英]Can one compose types in a Haskell instance declaration?
I've written a Haskell typeclass and it would be convenient to declare instances of it using types of the form (a -> m _)
, where m
is of kind (* -> *)
, such as a monad, and _
is a slot to be left unsaturated. 我已经编写了一个Haskell类型类,使用(a -> m _)
形式的类型来声明它的实例会很方便,其中m
是(* -> *)
,例如monad,而_
是保持不饱和的插槽。 I know how to write newtype X amb = X (a -> mb)
, and declaring an instance for X am
. 我知道如何编写新类型newtype X amb = X (a -> mb)
并声明X am
的实例。 But what I'm looking for is to instead use the bare, unwrapped ->
type, if that's possible. 但是我正在寻找的是,如果可能的话,使用裸露的,未包装的->
类型。
If one wants to declare instances for types of the form (a -> _)
, then you can just write: 如果要声明形式类型(a -> _)
实例,则可以这样写:
instance Foo a ((->) a) where ...
but I don't know how/whether one can do it with types of the form (a -> m _)
. 但我不知道如何/是否可以使用(a -> m _)
形式的类型。 I guess I'm looking to compose the type constructor (->) a _
and the type constructor m _
in my instance declaration. 我想我想在实例声明中组成类型构造函数(->) a _
和类型构造函数m _
。
I'd like to write something like this: 我想写这样的东西:
instance Foo a ((->) a (m :: *->*)) where ...
or: 要么:
instance Foo a ((->) a (m *)) where ...
but of course these don't work. 但是这些当然不起作用。 Is it possible to do this? 是否有可能做到这一点?
Concretely, here's what I'm trying to achieve. 具体来说,这就是我要实现的目标。 I wrote a typeclass for MonadReaders that are embedded inside (one level) of other MonadReaders, like this: 我为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
}
It'd be nice to also provide an instance something like this: 最好还提供一个如下所示的实例:
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
}
I think you're on the wrong track and are making things a lot more complicated than they need to be. 我认为您走在错误的轨道上,并且使事情变得比他们需要的复杂得多。
Some observations: 一些观察:
... ((->) w (m :: * -> *)) ... ...((->)w(m :: *-> *))...
Let's explore what you mean by this. 让我们探究您的意思。 You are using it for the type parameter m
in your DeepMonadReader
class, and therefore it needs to be a monad. 您正在将它用于DeepMonadReader
类中的类型参数m
,因此它必须是monad。 Can you give a concrete example of a monad which has this type? 您能举一个具有这种类型的单子的具体例子吗? Why not just use ((->) w)
? 为什么不只使用((->) w)
?
class MonadReader wm => DeepMonadReader wrm | class MonadReader wm => DeepMonadReader wrm | m -> r where ... m-> r哪里...
The fact that w
never apears in any member signatures is an indication something is amiss. 事实上, w
从未在任何成员的签名apears是一个迹象表明有什么不妥。
... I wrote a typeclass for MonadReaders that are embedded inside (one level) of other MonadReaders ... ...我为MonadReaders编写了一个类型类,该类嵌入在其他MonadReaders的内部(一个级别)中...
I would take the reverse perspective. 我会采取相反的观点。 It makes sense to talk of monad stacks which are a transformed version of another monad stack. 谈论monad堆栈是有意义的,它是另一个monad堆栈的转换版本。 Eg: 例如:
StateT s (WriterT w IO) "contains" IO
WriterT w (Maybe a) "contains" Maybe a
And what does it mean for a monad stack m1 to "contain" another monad m2 ? 单子堆栈m1 “包含”另一个单子m2是什么意思? It just means that there is a way to convert computations in m2 to computations in m1 : 这只是意味着有一种方法可以将m2中的计算转换为m1中的计算:
convert :: m2 a -> m1 a
Of course, this is just lift
when using monad transformers. 当然,使用monad变压器时,这只是lift
。
To express your concept of a monad reader embedded in another monad, I would use this type class: 为了表达您嵌入另一个monad中的monad阅读器的概念,我将使用以下类型类:
class HasReader m m' r where ...
deepAsk :: m r
deepLocal :: (r -> r) -> m' a -> m a
The idea here is that an instance HasReader mm' r expresses the fact that monad m "contains" a monad m' which itself is a reader with environment r . 这里的想法是,实例HasReader mm'r表示monad m “包含” monad m'的事实,而monad m'本身是具有环境r的阅读器。
deepAsk returns the environment of m' but as a computation in m . deepAsk返回M”,但在米计算环境。
deepLocal runs a computation in m' with a environment modification function but returns it as a computation in m . deepLocal使用环境修改函数在m'中运行计算,但将其作为m中的计算返回。 Note how this type signature is different from yours: my deepLocal uses different monads, m' and m whereas yours just goes from m to m . 请注意,此类型签名与您的类型签名有何不同:我的deepLocal使用不同的monad,分别为m'和m,而您的仅从m变为m 。
The next step is decide which triples (m, m', r) do we want to write instances of HasReader for. 下一步是确定我们要为其编写HasReader实例的三元组(m,m',r) 。 Clearly it seems you had instances like this in mind: 显然,您似乎已经想到了这样的实例:
m m' r
--------------------- ----------- --
ReaderT s (ReaderT r m) ReaderT r m r
ReaderT t (ReaderT s (ReaderT r m) ReaderT s (Reader T r m) s
...
but it also seems reasonable to want to have these instances: 但是要拥有这些实例似乎也很合理:
StateT s (ReaderT r m) ReaderT r m r
WriterT w (ReaderT r m) ReaderT r m r
MaybeT (ReaderT r m) ReaderT r m r
...
It turns out, though, that we don't need the HasReader class for any of these cases. 事实证明,在任何情况下我们都不需要HasReader类。 We can just write the expression as a computation in m' and lift
it up to m . 我们可以只写表达,比如M计算”,并lift
它为m。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.