首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >实现阅读器的monoid

实现阅读器的monoid
EN

Stack Overflow用户
提问于 2018-08-02 02:43:51
回答 2查看 161关注 0票数 1

我在这里的想法可能是天真的,但我认为如果Reader的右手边的值是Monoid的实例,那么可以为Reader定义一个Monoid……下面是我的实现:

代码语言:javascript
复制
instance Monoid a => Monoid (Reader r a) where
  mempty = pure mempty
  mappend ra rb = (<>) <$> ra <*> rb

但是,这会导致以下错误:

代码语言:javascript
复制
    • Illegal instance declaration for ‘Monoid (Reader r a)’
        (All instance types must be of the form (T t1 ... tn)
         where T is not a synonym.
         Use TypeSynonymInstances if you want to disable this.)
    • In the instance declaration for ‘Monoid (Reader r a)’
    |
413 | instance Monoid a => Monoid (Reader r a) where
    |                      ^^^^^^^^^^^^^^^^^^^

我不确定这个错误到底是什么意思,也不确定为什么我不能为Reader实现Monoid,尽管我认为这与Reader是一个更高级的类型有关?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-08-02 04:42:28

有两个问题。首先是这样的:

代码语言:javascript
复制
type Reader r = ReaderT r Identity

由于历史原因,不允许在实例声明中使用类型同义词。这是

代码语言:javascript
复制
where T is not a synonym.

错误的一部分。幸运的是,我们可以扩展同义词;这将给我们

代码语言:javascript
复制
instance Monoid a => Monoid (ReaderT r Identity a)

但现在我们会发现错误的另一部分,即:

代码语言:javascript
复制
All instance types must be of the form (T t1 ... tn)

具体地说,Identity不是类型变量,所以它不适合这种形式。同样,这种限制主要是由于历史原因而存在的。您可以通过启用两个语言扩展来取消这两个限制:

代码语言:javascript
复制
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}

然而,在这种情况下,它是不需要的。更可取的方法是实际使用指定的实例声明形式,因此:

代码语言:javascript
复制
instance (Applicative f, Monoid m) => Monoid (ReaderT r f m) where
    mempty = pure mempty
    mappend = liftA2 mappend

这不需要扩展,不仅适用于Reader,还适用于ReaderT转换任何Applicative实例。

但是,它确实会成为一个孤立实例;因此,您应该考虑编写另一个newtype包装器。

代码语言:javascript
复制
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- or, instead of GeneralizedNewtypeDeriving, write the obvious instances by hand
newtype App f m = App { getApp :: f m } deriving (Functor, Applicative)
instance (Applicative f, Monoid m) => Monoid (App f m) where
    mempty = pure mempty
    mappend = liftA2 mappend

然后,只要a是么半群,就可以将App (Reader r) a用作么半群。我似乎记得它已经存在于标准库中的某个地方,但我再也找不到它了……

票数 5
EN

Stack Overflow用户

发布于 2018-08-02 02:51:43

这里的问题是,您的Reader是一个类型别名,而不是newtype

Haskell2010不允许使用前者(这在允许的范围内非常保守),但如果您打开发布的错误中报告的扩展,则GHC允许在实例中使用类型别名。注意,在这种情况下,它将定义一个用于扩展别名的实例,例如

代码语言:javascript
复制
instance Monoid a => Monoid (r -> a) where ...

对于Reader类型,我更喜欢使用newtype,即使在使用时需要包装/拆开它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51640282

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档