Итак, у вас есть следующая подпись: foldMap :: (Monoid m, Foldable f) => (a -> m) -> f a -> m
. Давайте пошагово шаг за шагом
Ограничения:
a Monoid
- это данные, которые можно объединить с помощью какой-либо операции. Вы можете получить много примеров, если подумаете. Просто упомянуть здесь:
Integer
в качестве данных и +
в качестве операции. Элементы 1
и 2
могут быть объединены, давая 3 = 1 + 2
. Integer
как данные и *
как операция. Элементы 1
и 2
могут быть объединены, давая 2 = 1 * 2
. List
в качестве данных и ++
в качестве операции. Элементы [1,2]
и [2,3]
могут быть объединены, давая [1,2,2,3] = [1,2] ++ [2,3]
. Vector
размера 2 в качестве данных и +
в качестве операции. Элементы <1,2>
и <4,5>
могут быть объединены, давая <5,7> = <1,2> + <4,5>
. - и т. Д.
Все приведенные выше примеры имеют типичное представление Monoid
в haskell, типичноопределяется с помощью newtype
или data
ключевых слов. В haskell моноидная операция представлена как <>
.
Важным свойством является то, что моноиды имеют нейтральный элемент и являются ассоциативными. В контексте Integer
в соответствии с +
нейтральным элементом является 0
, ассоциативность определяется тем фактом, что (a + b) + c = a + (b + c)
. Вы можете легко найти эти свойства во всех приведенных примерах. Попробуйте!
Ограничение Foldable
стало проще. По сути, вы можете объединить структуру данных Foldable
в одно единственное значение.
Параметры функции
Код стоит тысячи слов, поэтому ...
foldMap :: (Monoid m, Foldable f) => (a -> m) -> f a -> m
-- ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^
-- |- We've seen this | |
-- | |- A 'Set' of a's which can be collapse into a single value
-- |- A function to convert a's into a monoid
Итак, по определению вы можете легко следовать этому рассуждению / алгоритму:
Помещения
- У меня есть структура элементов, которую можно свернуть в одно значение
- У меня есть способ преобразовать эти элементы в элемент моноида
- Моноиды имеют нейтральный элемент
- Два элемента моноидов можно объединить вместе
Алгоритм
- Свернуть элементыструктура, объединяя их, используя оператор моноида
- , если структура пуста, используйте нейтральный элемент в качестве результата.
очень необычно, но ... я все еще не понимаю
Проблема в том, что когда вы определяете экземпляр Foldable
, вы еще не определили, как сложить структуру, и это отличается для каждого из них !. Как и в ответе Виллема, вы можете определить foldMap
в терминах foldr
, что означает, что foldr
определяет способ разрушения вашей структуры. Viceversa также верно: вы можете определить foldr
в терминах foldMap
, и, вероятно, это ошибка !! если вы не определили foldr
, универсального способа реализации foldMap
не существует, это будет зависеть от вашей структуры данных. Итак, в качестве кода-sumary:
class Foldable t where
foldMap :: Monoid m => (a -> m) -> t a -> m -- A default instance can be provided if you define foldr (a.k.a a way to collapse the structure)
foldr :: (a -> b -> b) -> b -> t a -> b -- A default instance can be provided if you define foldMap (a.k.a a way to collapse the structure into a monoid element)
-- but if you don't provide at least one, It'll be impossible to implement any
-- because you aren't telling me how to collapse the structure!!