Что делает concatMap
?
Я знаю, что делают concat
и map
. Разве только они вместе взяты или это совершенно другая функция?
Что делает concatMap?
Ответ 1
Концептуально, да, , но фактическая реализация actual implementation отличается:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = foldr ((++) . f) []
Ответ 2
Да, функция concatMap
- это просто concat
и map
вместе взятые. отсюда и название. Объединение функций просто означает их составление:
(.) :: (b -> c) -> (a -> b) -> a -> c
Однако concat
и map
нельзя соединить, просто используя композицию функций из-за сигнатуры типа map
:
map :: (a -> b) -> [a] -> [b]
-------- --- ---
a b c
Как вы можете видеть, композиция функций ожидает функцию типа a -> b
, но map
имеет тип a -> b -> c
. Чтобы создать concat
с map
, вам нужно использовать вместо этого оператор .:
:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
Функция concat
имеет сигнатуру типа:
concat :: [[a]] -> [a]
----- ---
c d
Следовательно, concat .: map
имеет тип:
concat .: map :: (a -> [b]) -> [a] -> [b]
---------- --- ---
a b d
Что совпадает с concatMap
:
concatMap :: (a -> [b]) -> [a] -> [b]
Сам оператор .:
можно записать в терминах композиции функций:
(.:) = (.) (.) (.)
-- or
(.:) = (.) . (.)
Следовательно, concatMap
можно записать как:
concatMap = (.) (.) (.) concat map
-- or
concatMap = (concat .) . map
-- or
concatMap = concat .: map
Если вы flip
рассуждаете по аргументам concatMap
, вы получаете функцию >>=
(связывание) монады списка:
instance Monad [] where
return x = [x]
(>>=) = flip concatMap
fail _ = []
flip concatMap :: [a] -> (a -> [b]) -> [b]
>>= :: Monad m => m a -> (a -> m b) -> m b
Это делает ее такой же, как функция =<<
монады списка:
concatMap :: (a -> [b]) -> [a] -> [b]
=<< :: Monad m => (a -> m b) -> m a -> m b
Итак, теперь вы знаете все, что нужно знать о concatMap
. Это просто concat
применяется к результату map
. Отсюда и название.
Ответ 3
Проверка документации показывает:
concatMap :: (a -> [b]) -> [a] -> [b]
Сопоставить функцию над списком и объединить результаты
И что его определение таким образом:
-- | Map a function over a list and concatenate the results.
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = foldr ((++) . f) []
Сравните следующий вывод из ghci:
*Main> concatMap (++"! ") ["one", "two", "three"]
"one! two! three! "
*Main> concat $ map (++"! ") ["one", "two", "three"]
"one! two! three! "