Складные и моноидные типы - PullRequest
0 голосов
/ 12 октября 2018

Я пытаюсь написать функции, которые добавляют и умножают все элементы в списке, используя моноиды и Foldable.Я установил некоторый код, который, на мой взгляд, работает:

data Rose a = a :> [Rose a]
    deriving (Eq, Show)

instance Functor Rose where
    fmap f rose@(a:>b) = (f a :> map (fmap f) b) 

class Monoid a where
    mempty ::           a
    (<>)   :: a -> a -> a

instance Monoid [a] where
    mempty = []
    (<>)   = (++)

newtype Sum     a = Sum     { unSum     :: a } deriving (Eq, Show)
newtype Product a = Product { unProduct :: a } deriving (Eq, Show)

instance Num a => Monoid (Sum a) where
    mempty           = Sum 0
    Sum n1 <> Sum n2 = Sum (n1 + n2)

instance Num a => Monoid (Product a) where
    mempty                   = Product 1
    Product n1 <> Product n2 = Product (n1 * n2)

class Functor f => Foldable f where
    fold    :: Monoid m =>             f m -> m
    foldMap :: Monoid m => (a -> m) -> f a -> m
    foldMap f a = fold (fmap f a)

instance Foldable [] where
    fold = foldr (<>) mempty

instance Foldable Rose where
    fold (a:>[]) = a <> mempty
    fold (a:>b)  = a <> (fold (map fold b))

А затем, после определения различных экземпляров Foldable и типов Sum и Product, я хочу определить две функции, которые добавляют соответственно умножение элементов вструктура данных, но это дает ошибки, которые я не знаю, как интерпретировать, я должен признать, что это была скорее работа с догадками, чем реальная логика, поэтому было бы желательно подробное объяснение вашего ответа.

fsum, fproduct :: (Foldable f, Num a) => f a -> a
fsum b     = foldMap Sum b
fproduct b = foldMap Product b

Ошибка:

Assignment3.hs:68:14: error:
    * Occurs check: cannot construct the infinite type: a ~ Sum a
    * In the expression: foldMap Sum b
      In an equation for `fsum': fsum b = foldMap Sum b
    * Relevant bindings include
        b :: f a (bound at Assignment3.hs:68:6)
        fsum :: f a -> a (bound at Assignment3.hs:68:1)
   |
68 | fsum b     = foldMap Sum b
   |              ^^^^^^^^^^^^^

Assignment3.hs:69:14: error:
    * Occurs check: cannot construct the infinite type: a ~ Product a
    * In the expression: foldMap Product b
      In an equation for `fproduct': fproduct b = foldMap Product b
    * Relevant bindings include
        b :: f a (bound at Assignment3.hs:69:10)
        fproduct :: f a -> a (bound at Assignment3.hs:69:1)
   |
69 | fproduct b = foldMap Product b
   |              ^^^^^^^^^^^^^^^^^

1 Ответ

0 голосов
/ 12 октября 2018

Если вы используете Sum (или Product) в foldMap, вы сначала отобразите элементы в Foldable на Sum с (или Product с),Поэтому результат fsum будет - как вы его определили - Sum a, а не a:

fsum :: (Foldable f, Num a) => f a -> <b>Sum a</b>
fsum b = foldMap Sum b

, чтобы извлечь значение, заключенное в конструктор SumВы можете получить его с помощью unSum :: Sum a -> a getter:

fsum :: (Foldable f, Num a) => f a -> <b>a</b>
fsum b = <b>unSum (</b>foldMap Sum b<b>)</b>

или после eta-Reduction :

fsum :: (Foldable f, Num a) => f a -> a
fsum = unSum . foldMap Sum

То же самое должно произойти для Product.

...