简体   繁体   English

一个Haskell实例声明中可以组成类型吗?

[英]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 . deepLo​​cal使用环境修改函数在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 . 请注意,此类型签名与您的类型签名有何不同:我的deepLo​​cal使用不同的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM