2016-10-13 2 views
8

Все это время, когда любая лекция Haskell говорила о «плоской карте», как правило, по отношению к Монадам, я думал, что она называется «плоской» по какой-то причине, то есть она сглаживает контейнер , Такfmap и «плоская карта» в Haskell

[[1,2],[3,4]] 

будет обрабатываться так же, как если бы это было

[1,2,3,4] 

Но теперь я обнаружил, что БПМЖ и карта в основном то же самое, с той лишь разницей является применение одного функторов и другой для просто списков. И это было сделано только в конце, чтобы избежать путаных сообщений об ошибках при использовании карты.

Это правда? И если да, то почему f в fmap означает «плоский», почему бы не «functor map»?

+3

'f' в' fmap' не означает 'flat'. Эквивалентом 'flatMap' в Haskell является' (>> =) '. Сначала была определена функция 'map' для списков, поэтому для более общей функции' fmap' было необходимо другое имя. – Lee

+3

Скорее, 'fmap' является обобщением' map' другим функторам, кроме функтора списка. Тот, кто сказал вам, что «fmap» был коротким для «плоской карты», ошибся. – chepner

+4

Вы уверены, что лекция, на которую вы ссылались, имела в виду «fmap», когда говорила «плоская карта»? Было бы разумнее, если бы речь шла о 'concatMap' (aka' >> = '), который часто называют« flatMap »на других языках и ведет себя так, как вы ожидали. – sepp2k

ответ

19

И если да, то почему f в fmap означать «плоский», почему не «функтор карта»?

Интуиция прав: f в fmapделает стенд для «функтора карты», а не «плоско карте» на всех. На самом деле, в более новых, подобных языках, таких как PureScript, это просто map. Haskell map был сначала определен для списков, поэтому появление нового имени было затруднительным. Использование F от Functor было легким, если не особенно творческим, выбором.

Скорее всего, лектор имел в виду функцию монадического связывания, >>=. Из-за эквивалентности x >>= fjoin (fmap f x) связывание также иногда называют flatMap на других языках. Он имеет поведение, которое вы ожидаете в списках, например:

> [1,2,3] >>= \x -> [x,x] 
[1,1,2,2,3,3] 

Это важно иметь в виду, однако, что это «плоская карта» не рекурсивно расплющить произвольную глубину. На самом деле, запись такой функции в Haskell на самом деле невозможна без какой-либо сложной трюки. Попробуйте сами: как бы выглядела подпись типа для функции flatten, даже той, которая работает непосредственно в списках?

flatten :: ??? -> [a] 

>>= функция очень простым по сравнению: это как fmap, но каждый выходной элемент должен быть обернут в функторе и >>= неглубоко «сглаживает» результаты в одной упаковке. Эта операция является сущностью того, что такое монада, поэтому функция >>= живет в классе Monad, но fmap находится в Functor.

Этот ответ взят из некоторых комментариев по исходному вопросу, поэтому я отметил его в сообществе wiki. Изменения и улучшения приветствуются.

+0

Это не просто цифры, хотя даже список, когда есть разные глубины, '[[[1,2]], [3], [4]] >> = \ x -> x' производит только' :: (Num [t], Num t) => [[t]] ', а не' [[1,2], 3,4] '. – trans

+0

@trans Обратите внимание, что '[[[1,2]], [3], [4]]' не является допустимым значением Haskell.У него нет типа - это не 'Num t => [[t]]' и 'Num t => [[[t]]]', потому что глубина не согласована. –

+0

Причина, по которой вы получаете этот тип, связана с тем, что работает 'Num', поэтому он выводит тип' Num t => [[t]] ', где он ожидает' [1, 2] ', чтобы иметь' Num' пример. Конечно, нет. Попробуйте с не-номерами, чтобы получить более четкие результаты. –

0

Вот некоторые явные эквивалентные примеры того, как делать flatMap в Haskell. не

Prelude> map (replicate 3) [1..4] 
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]] 
Prelude> fmap (replicate 3) [1..4] 
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]] 
Prelude> concat [[1,2],[3,4]] 
[1,2,3,4] 
Prelude> concat (map (replicate 3) [1..4]) 
[1,1,1,2,2,2,3,3,3,4,4,4] 
Prelude> concat $ map (replicate 3) [1..4] 
[1,1,1,2,2,2,3,3,3,4,4,4] 
Prelude> concatMap (replicate 3) [1..4] 
[1,1,1,2,2,2,3,3,3,4,4,4] 
Prelude> replicate 3 `concatMap` [1..4] 
[1,1,1,2,2,2,3,3,3,4,4,4] 
Prelude> [1..4] >>= replicate 3 
[1,1,1,2,2,2,3,3,3,4,4,4] 

Должно быть ясно, что flatMap является карта первым, а затем плоско, вы расплющить выход карты, в отличие от уплощения списка ввода вы собираетесь обрабатывать (это не flatMap, это не имеет имя, это просто квартира, а затем карта).

Смежные вопросы