ZipList Monoid haskell - PullRequest
       9

ZipList Monoid haskell

0 голосов
/ 02 мая 2018

Моноид по умолчанию для списков в прелюдии GHC - это конкатенация.

[1,2,3] <> [4,5,6] становится [1,2,3] ++ [4,5,6] и, таким образом, [1,2,3,4,5,6]

Я хочу написать экземпляр моноида ZipList, который ведет себя так:

[
  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, чтобы создать экземпляр для Monoid, Arbitrary и EqProp. Таким образом избегая сиротских случаев. Вот как ZipList и Sum выглядят в Prelude:

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

Вот так выглядит мой новый тип 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 голосов
/ 02 мая 2018

Первое замечание: ZipList экземпляр *1001* уже имеет поведение 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 (<>) от выражения, которое я написал выше.

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 следует есть zippy Monoid экземпляр из коробки, но, увы, нет.)

Ваш желаемый Monoid тогда просто Ap ZipList (Sum Int). Это эквивалентно MyZipList Monoid, который вы написали от руки (за исключением ошибки в вашем mempty - это должно быть MyZipList $ ZipList $ repeat mempty), но составление его из повторно используемых newtype, как это менее Специально и требует меньше шаблонного.

...