【问题标题】:Can one compose types in a Haskell instance declaration?可以在 Haskell 实例声明中组合类型吗?
【发布时间】:2016-06-19 22:17:36
【问题描述】:

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

但是这些当然是行不通的。可以这样做吗?

具体来说,这就是我想要实现的目标。我为 嵌入在(一层)其他 MonadReader 中的 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
  }

【问题讨论】:

    标签: haskell typeclass


    【解决方案1】:

    我认为你走错了路,而且做得更多 比他们需要的复杂。

    一些观察:

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

    让我们来探讨一下您的意思。您在DeepMonadReader 类中将它用于类型参数m,因此它需要是一个单子。你能举一个单子的具体例子吗 有这种类型吗?为什么不直接使用((-&gt;) w)

    类 MonadReader w m => DeepMonadReader w r m | m -> r 其中 ...

    w 从未出现在任何成员签名中这一事实表明有问题。

    ...我为 MonadReaders 编写了一个类型类,它嵌入到其他 MonadReaders(一个级别)中...

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

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

    单子堆栈m1“包含”另一个单子m2是什么意思? 这只是意味着有一种方法可以将 m2 中的计算转换为 m1 中的计算:

    convert ::  m2 a -> m1 a
    

    当然,这只是 lift 在使用 monad 转换器时。

    为了表达您对嵌入另一个 monad 的 monad reader 的概念,我会使用这个 类型类:

    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 而你的只是从 mm。

    下一步是决定我们要编写哪些三元组 (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

    【讨论】:

    • 谢谢你。您提出了几个建议:(1)我将实例的类型更改为(->)w,或者将类的第一个参数从外部 Reader 环境的类型更改为外部 Reader monad 的类型。 (2) 那我改变deepLo​​cal的类型。 (3) 我可能想要只有一个 Readers 层的 monad 堆栈的类的实例;而且在很多这样的情况下,这个类并没有那么有用或必要。
    • 回应(1):这值得探索,谢谢。 Re (2): 我需要一个我描述的类型的 deepLo​​cal;尽管就您提出的 deepLo​​cal 而言,我还没有看到构建它的优势。我会考虑的。
    • Re (3): 实际上我们不需要 HasReader 类来处理你的第二组案例,我们也不需要自己做lifting,因为它已经写好了进入 m monads 的 MonadReader 实例。我的DeepMonadReader 类适用于堆栈中的外部 MonadReader“妨碍”更深入嵌入的 MonadReader 的情况,从而使后者的 asklocal 方法更难访问。当然,仍然可以使用liftmapReader 等的正确组合来解决它们;但这些组合并不总是显而易见的......
    • Re (3) - 你为什么不举一个你想使用 DeepReader 类的具体例子,我们会看看有什么选项。
    • 继续讨论chat...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    相关资源
    最近更新 更多