ZipList Monoid haskell [英] ZipList Monoid haskell

查看:127
本文介绍了ZipList Monoid haskell的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

GHC前奏中列表的默认monoid是串联.

The default monoid for lists in the GHC Prelude is concatenation.

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

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

I want to write a ZipList Monoid instance that behaves like this:

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

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

The result is [5,7,9] assuming I am using the sum monoid. Note this behaves like zipWith (+)

可能它的行为如下:

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

我需要围绕 ZipList 新类型和 Sum 新类型创建一个新类型,以便为 Monoid 创建实例任意 EqProp .从而避免了孤立实例.这是 ZipList Sum Prelude 中的样子:

I need to create a newtype around the ZipList newtype and the Sum newtype in order to create an instance for Monoid, Arbitrary, and EqProp. Thus avoiding orphan instances. This is how both the ZipList and the Sum looks like in the Prelude:

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

这是我的新类型 MyZipList 的外观:看起来正确吗?

This is how my newtype MyZipList looks: Does it look right?

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

这是我的新类型 MySum 的外观:这看起来正确吗?

This is how my newtypeMySum looks like: Does this look right?

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

我想帮助我找出哪里出了问题.

I would like assistance in finding out where I went wrong.

推荐答案

首先请注意, ZipList Applicative 实例已经具有所需的zippy行为.

First note that ZipList’s Applicative instance already has the zippy behaviour you want.

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

然后利用以下事实:任何 Applicative 都会通过单调函子自身提升其内容的单调行为,从而产生 Monoid .计划是从我上面编写的表达式中提取 liftA2(<>)模式.

Then use the fact that any Applicative gives rise to a Monoid by lifting the monoidal behaviour of its contents through the monoidal functor itself. The plan is to abstract the liftA2 (<>) pattern from the expression I wrote above.

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 实例,但是,可惜没有.)

(As far as I know this newtype is missing from base, which seems like an oversight to me, though there may be a good reason for it. In fact, I’d argue that ZipList should have a zippy Monoid instance out of the box, but, alas, it doesn’t.)

您所需的 Monoid 就是 Ap ZipList(Sum Int).这等效于您手工编写的 MyZipList Monoid (除了 mempty 中的错误-它应该是 MyZipList $ ZipList$ repeat mempty ),但是像这样用可重用的 newtype 组成它是临时性的,并且需要更少的样板.

Your desired Monoid is then just Ap ZipList (Sum Int). This is equivalent to the MyZipList Monoid you wrote by hand (except for the mistake in your mempty - it should be MyZipList $ ZipList $ repeat mempty), but composing it out of reusable newtypes like this is less ad-hoc and requires less boilerplate.

这篇关于ZipList Monoid haskell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆