可以在Haskell实例声明中组合类型吗?

时间:2016-06-19 11:46:34

标签: haskell typeclass

我编写了一个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 个答案:

答案 0 :(得分:2)

我认为你走错了轨道并且正在制造更多东西 比他们需要的要复杂。

一些观察结果:

  

...(( - &gt;)w(m :: * - &gt; *))...

让我们来探讨你的意思。您正在将其用于m类中的类型参数DeepMonadReader,因此它必须是monad。你能给出一个monad的具体例子吗? 有这种类型?为什么不使用((->) w)

  

类MonadReader w m =&gt; DeepMonadReader w r m | m - &gt;在哪里......

w永远不会出现在任何成员签名中这一事实表明有些不妥。

  

...我为MonadReaders编写了一个类型类,它嵌入了其他MonadReaders的内部(一级)......

我会采取相反的观点。谈论转换的monad堆栈是有意义的 另一个monad堆栈的版本。 E.g:

StateT s (WriterT w IO)   "contains"     IO
WriterT w (Maybe a)       "contains"     Maybe a

对于monad堆栈 m1 来说,“包含”另一个monad m2 意味着什么? 它只是意味着有一种方法可以将 m2 中的计算转换为 m1 中的计算:

convert ::  m2 a -> m1 a

当然,使用monad变换器时这只是lift

为了表达你在另一个monad中嵌入的monad阅读器的概念,我会用它 类型类:

class HasReader m m' r where ...
  deepAsk :: m r
  deepLocal :: (r -> r) -> m' a -> m a

这里的想法是实例 HasReader m m'r 表达了这样的事实 monad m “包含”monad m'本身就是一个读者 环境 r

deepAsk 会返回 m'的环境,但会在 m 中进行计算。

deepLo​​cal 使用环境修改功能在 m'中运行计算 但是将其作为 m 中的计算返回。请注意此类型签名与您的签名有何不同: 我的 deepLo​​cal 使用不同的monad, m' m ,而你的 m m < /强>

下一步是决定我们要编写实例的三元组(m,m',r) HasReader 的用途。很明显,你似乎有这样的例子:

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
...

但想要拥有这些实例似乎也是合理的:

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
...

但事实证明,对于任何这些情况,我们都不需要 HasReader 类。 我们可以将表达式编写为 m'中的计算,将lift表达为 m