ZipList Monoid haskell

时间:2018-05-02 08:36:59

标签: haskell monoids

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],假设我正在使用总和幺半群。 请注意,此行为与zipWith (+)

类似

可能会表现得像这样:

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

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

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

这就是我的newtype 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

这就是我的newtype MySum的样子: 这看起来不错吗?

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

我想帮助找出我哪里出错。

1 个答案:

答案 0 :(得分:6)

首先请注意,ZipList的{​​{1}}实例已经具有您想要的zippy行为。

Applicative

然后使用任何ghci> liftA2 (<>) (Sum <$> ZipList [1,2,3]) (Sum <$> ZipList [4,5,6]) :: ZipList Int ZipList [Sum 5, Sum 7, Sum 9] 通过幺半体仿函数本身提升其内容的幺半群行为而产生Applicative的事实。计划是从我上面写的表达式中抽象Monoid模式。

liftA2 (<>)

(据我所知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 newtype遗漏base,这似乎是对我的疏忽,虽然可能有充分的理由。事实上,我认为ZipList应该有一个开箱即用的Monoid实例,但是,唉,它没有。)

您想要的Monoid只是Ap ZipList (Sum Int)。这相当于您手动编写的MyZipList Monoidmempty中的错误除外 - 它应该是MyZipList $ ZipList $ repeat mempty),但是可以用可复制的{{{ 1}}这样的事情不那么特别,需要较少的样板。