【问题标题】:ZipList Monoid haskellZipList Monoid haskell
【发布时间】:2018-05-02 08:36:58
【问题描述】:

GHC Prelude 中列表的默认 monoid 是串联。

[1,2,3] <> [4,5,6] 变为 [1,2,3] ++ [4,5,6] 并因此变为 [1,2,3,4,5,6]

我想编写一个行为如下的 ZipList Monoid 实例:

[
  1 <> 4
, 2 <> 5
, 3 <> 6
]

结果是 [5,7,9] 假设我使用的是 sum monoid。 请注意,这类似于zipWith (+)

它的行为可能是这样的:

[
  Sum 1 <> Sum 4
, Sum 2 <> Sum 5
, Sum 3 <> Sum 6
]

我需要围绕ZipList 新类型和Sum 新类型创建一个新类型,以便为MonoidArbitraryEqProp 创建一个实例。 从而避免孤儿实例。 这就是ZipListSumPrelude 中的样子:

newtype ZipList a = ZipList { getZipList :: [a] }
newtype Sum a = Sum { getSum :: a }

这就是我的新类型MyZipList 的样子:看起来对吗?

newtype MyZipList a =
  MyZipList (ZipList [a])
  deriving (Eq, Show)

instance Monoid a => Monoid (MyZipList a) where
  mempty = MyZipList (ZipList [])

  mappend (MyZipList z) (MyZipList z') =
    MyZipList $ liftA2 mappend z z'

instance Arbitrary a => Arbitrary (MyZipList a) where
  arbitrary = MyZipList <$> arbitrary

instance Eq a => EqProp (MyZipList a) where
  (=-=) = eq

这就是我的 newtypeMySum 的样子: 这看起来对吗?

newtype MySum a =
  MySum (Sum a)
  deriving (Eq, Show)

 instance (Num a, Monoid a) => Monoid (MySum a) where
   mempty = MySum mempty

   mappend (MySum s) (MySum s') = MySum $ s <> s'

 instance Arbitrary a => Arbitrary (MySum a) where
   arbitrary = MySum <$> arbitrary

我需要帮助找出我出错的地方。

【问题讨论】:

  • 但是x &lt;&gt; mempty == mempty &lt;&gt; x == x(这是幺半群的属性之一),在你的情况下是mempty &lt;&gt; x == mempty。我认为在ZipList 的情况下,mappend 应该等于memptys(a 类型)的无限列表。
  • 为什么要创建一个新的 newtype 而不是为ZipList a 添加一个 Monoid 实例?
  • @DominiqueDevriese "我需要创建一个新类型...从而避免孤儿实例。"
  • 如果您的目标是让MySum 的行为与Sum 完全相同,那么至少看起来是正确的。虽然我不确定你为什么要包装SumZipList,但如果你要重新实现它们的行为——你不妨直接构建MySumMyZipList。话虽如此,你说你需要帮助,但你实际上并没有说你的问题是什么。您很好地解释了您的实际操作,但您的问题缺少对实际问题的描述。

标签: haskell monoids


【解决方案1】:

首先请注意,ZipListApplicative 实例已经具有您想要的 zippy 行为。

ghci> liftA2 (<>) (Sum <$> ZipList [1,2,3]) (Sum <$> ZipList [4,5,6]) :: ZipList Int
ZipList [Sum 5, Sum 7, Sum 9]

然后使用任何Applicative 产生Monoid 的事实,通过单曲面函子本身提升其内容的单曲面行为。计划是从我上面写的表达式中抽象出liftA2 (&lt;&gt;) 模式。

newtype Ap f a = Ap { getAp :: f a }
instance (Applicative f, Monoid a) => Monoid (Ap f a) where
    mempty = Ap $ pure mempty
    Ap xs `mappend` Ap ys = Ap $ liftA2 mappend xs ys

(据我所知,base 中缺少 newtype,这对我来说似乎是一个疏忽,尽管可能有充分的理由。事实上,我认为 ZipList 应该有一个开箱即用的 zippy Monoid 实例,但是,唉,它没有。)

您想要的Monoid 就是Ap ZipList (Sum Int)。这相当于您手写的MyZipListMonoid(除了您的mempty 中的错误-应该是MyZipList $ ZipList $ repeat mempty),但是像这样用可重复使用的newtypes 编写它的广告更少- hoc 并且需要更少的样板。

【讨论】:

  • 这里有没有办法使用Compose
  • @chepner 我猜是Ap f = Compose f Identity,但遗憾的是Compose doesn't have the Monoid instance we'd want either
  • @BenjaminHodgson 您将如何为quickBatch 测试实施Arbitrary (Ap f a)?我尝试了instance Arbitrary a =&gt; Arbitrary (Ap f a) where arbitrary = liftA2 (&lt;&gt;) Ap arbitrary arbitrary 和其他一些变体,但都没有奏效..
  • 你想重用ZipListArbitrary,对吧? instance Arbitrary (f a) =&gt; Arbitrary (Ap f a) where arbitrary = Ap arbitrary
  • arbitrary = Ap &lt;$&gt; arbitrary,我的错
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多