ZipList Monoid haskell

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

[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 новый тип и 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 ответ

Первое замечание, что ZipList"s 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), Это эквивалентно MyZipListMonoid Вы написали от руки (за исключением ошибки в вашем mempty - так должно быть MyZipList $ ZipList $ repeat mempty), но составляя его из многоразового использования newtypeКак будто это менее специализировано и требует меньше шаблонов.

Другие вопросы по тегам