Напишите максимальный моноид, используя Maybe в Haskell - PullRequest
12 голосов
/ 17 марта 2011

Я прошел через моноиды Haskell и их использование , что дало мне довольно хорошее понимание основ моноидов. Одна из вещей, представленных в сообщении в блоге, это любой моноид, и его использование выглядит следующим образом:

foldMap (Any . (== 1)) tree
foldMap (All . (> 1)) [1,2,3]

Аналогичным образом я пытался построить максимальный моноид и придумал следующее:

newtype Maximum a = Maximum { getMaximum :: Maybe a }
        deriving (Eq, Ord, Read, Show)

instance Ord a => Monoid (Maximum a) where
        mempty = Maximum Nothing
        m@(Maximum (Just x)) `mappend` Maximum Nothing = m
        Maximum Nothing `mappend` y = y
        m@(Maximum (Just x)) `mappend` n@(Maximum (Just y))
          | x > y = m
          | otherwise = n

Я мог бы создать максимальный моноид для определенного типа - скажем, Num, например, довольно легко, но хотел бы, чтобы он был полезен для чего угодно (с очевидным требованием, чтобы что-нибудь было экземпляром Ord).

На данный момент мой код компилируется, но это все. Если я попытаюсь запустить его, я получу это:

> foldMap (Just) [1,2,3]

<interactive>:1:20:
    Ambiguous type variable `a' in the constraints:
      `Num a' arising from the literal `3' at <interactive>:1:20
      `Monoid a' arising from a use of `foldMap' at <interactive>:1:0-21
    Probable fix: add a type signature that fixes these type variable(s)

Я не уверен, если это потому, что я называю это неправильно, или потому что мой моноид неправильный, или оба. Я был бы признателен за любые указания о том, где я ошибаюсь (как с точки зрения логических ошибок, так и не-идиоматического использования Haskell, так как я очень плохо знаком с языком).

- РЕДАКТИРОВАТЬ -

Пол Джонсон в комментарии ниже предложил опустить «Может быть». Моя первая попытка выглядит так:

newtype Minimum a = Minimum { getMinimum :: a }
        deriving (Eq, Ord, Read, Show)

instance Ord a => Monoid (Minimum a) where
        mempty = ??
        m@(Minimum x) `mappend` n@(Minimum y)
          | x < y     = m
          | otherwise = n

но мне неясно, как выразить mempty, не зная, каким должно быть значение ampty. Как я могу обобщить это?

1 Ответ

12 голосов
/ 17 марта 2011

Функция, переданная в foldMap, должна возвращать моноид, в этом случае типа Maximum a:

> foldMap (Maximum . Just) [1,2,3]
Maximum {getMaximum = Just 3}
...