Как превратить функцию, возвращающую [a], в функцию, возвращающую моноид? - PullRequest
1 голос
/ 07 июня 2019

Я играю с полиморфизмом возвращаемого типа Haskell, используя следующую функцию:

f :: [a] -> [a]
f [] = mempty
f (x:xs) = [x] <> f xs

Очевидно, это ничего не делает. Я хотел бы изменить тип так, чтобы он брал список и возвращал контейнер Monoid, один из которых мог бы быть списком. Я застрял здесь, потому что Monoid принимает один аргумент типа. Я понятия не имею, что тип может быть: f :: Monoid m => [a] -> ?

Возможно ли это?

Ответы [ 2 ]

9 голосов
/ 07 июня 2019

Как вы заметили, вы не можете превратить произвольный a в член какого-либо конкретного моноида m без функции типа a -> m.Но нет такой функции, которая бы работала для всех Моноидных экземпляров - если бы они были, они должны были бы быть в определении класса типов, и вы можете видеть, что их не существует.

Следовательно, вы должны либо специализировать f для конкретного моноида, как вы делали здесь для [a] моноида;или принять функцию преобразования a -> m в дополнение к [a].То есть ваш тип может стать следующим:

combine :: Monoid m => (a -> m) -> [a] -> m

И если мы спросим у Google об этом типе , мы увидим, что ваша функция уже определена (обобщающий список для Foldable):

foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m

Вы можете найти полезным упражнение для реализации foldMap, либо для складных таблиц в целом, либо для специализированных списков.

3 голосов
/ 07 июня 2019

Как сказал @ amalloy , вам нужен способ поместить содержимое вашего списка в ваш "моноидный контейнер" - класс Monoid не определяет такую ​​вещь, поэтому либо содержимое вашего списка уже должно составлятьmonoid (в этом случае ваша функция просто mconcat):

f :: Monoid m => [m] -> m
f = mconcat

или вы предоставляете функцию преобразователя (в этом случае вы преобразуете содержимое списка в моноид, , затем do mconcat:

f :: Monoid m => (a -> m) -> [a] -> m
f converter = mconcat . fmap converter
...