首页 文章

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

提问于
浏览
1

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

  • 2

    我认为你走错了路,并且使事情变得比他们需要的复杂得多 .

    一些观察:

    ...(( - >)w(m :: * - > *))...

    让我们来探讨你的意思 . 您在 DeepMonadReader 类中使用它作为类型参数 m ,因此它需要是monad . 你能给出一个具有这种类型的monad的具体例子吗?为什么不直接使用 ((->) w)

    类MonadReader w m => DeepMonadReader w r m | m - > r哪里......

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

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

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

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

    对于monad堆栈 m1 到"contain"另一个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 "contains" monad m' 这个本身就是环境 r 的读者的事实 .

    deepAsk 返回 m' 的环境,但作为 m 中的计算 .

    deepLocal 使用环境修改函数在 m' 中运行计算,但在 m 中将其作为计算返回 . 请注意这种类型签名与你的签名有何不同:我的 deepLocal 使用不同的monad, m'm 而你的签名只是从 mm .

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

    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 .

相关问题