Чому у нас є карта, fmap та liftM?


102
map :: (a -> b) -> [a] -> [b]

fmap :: Functor f => (a -> b) -> f a -> f b

liftM :: Monad m => (a -> b) -> m a -> m b

Чому у нас є три різні функції, які роблять по суті те саме?


32
Історія, в основному. fmap відрізняється від карти з педагогічних причин, liftM відрізняється від fmap з історичних причин (а саме Functor не є суперкласом Монади)
luqui

12
О, і просто для того, щоб зрозуміти: вони "по суті" не роблять те саме. І те, mapі інше, liftMбезумовно, має робити саме те саме fmap.
CA McCann

2
Хоча fmapі liftMробиш абсолютно те саме, mapзвичайно, це лише окремий випадок, тобто щось інше. fmap id getLineє добре набраним, тоді map id getLineяк ні.
Торстен

Відповіді:


91

mapіснує спрощення операцій зі списками та з історичних причин (див. Який сенс карти в Haskell, коли є fmap? ).

Ви можете запитати, навіщо нам потрібна окрема функція карти. Чому б просто не усунути поточну функцію лише для списку карт, а перейменувати fmap на карту? Ну, це гарне запитання. Звичайний аргумент полягає в тому, що хтось просто вивчає Haskell, коли неправильно використовувати карту, швидше побачить помилку щодо списків, ніж про Functors.

- Типкласопедія , сторінка 20

fmapі liftMіснують, тому що монади не були автоматично функціонерами в Haskell:

Той факт, що у нас є і fmap, і liftM - прикрий наслідок того, що для класу типу Monad не потрібен екземпляр Functor, хоча математично кажучи, кожна монада є функтором. Однак, fmap і liftM по суті є взаємозамінними, оскільки помилка (в соціальному, а не технічному розумінні) для будь-якого типу є екземпляром Monad, не будучи також екземпляром Functor.

- Типкласопедія , стор. 33

Редагувати: історія agustuss mapта fmap:

Це насправді не так, як це відбувається. Сталося те, що тип карти було узагальнено для покриття Functor в Haskell 1.3. Тобто, в Haskell 1.3 fmap називали картою. Потім цю зміну було повернено в Haskell 1.4 і було введено fmap. Причиною цієї зміни була педагогічна; при навчанні Haskell для початківців дуже загальний тип карти робив повідомлення про помилки важче зрозуміти. На мою думку, це був не правильний спосіб вирішення проблеми.

- Який сенс карти в Haskell, коли є fmap?


13
І з моєї точки зору як того, хто вперше стикався з Haskell більше десяти років після того, як описана зміна @augustss, і витратив багато часу на допомогу людям, які зараз вивчають мову, зовсім не зрозуміло, що це навіть допомогло в будь-яким способом. Звичайно, недостатньо, щоб компенсувати марну надмірність (що саме призводить до того, що люди задають такі питання); Functorклас занадто часто , щоб ігнорувати, і новачки часто плутаються повідомлення про помилки в будь-якому випадку!
CA McCann

10
Чи не можемо ми просто зняти liftM? Нехай код зламається, кого це хвилює, зазвичай це займає менше 2 днів, щоб код було зафіксовано на github і потім завантажено під час злому. Або я дикий і божевільний?
Тарраш

1
@Tarrasch: не всі користуються github, не всі пакунки мають чудовий трек для того, щоб оновитись вчасно, і я для одного, як правило, використовую, liftMхоча в do-блоці, а не fmapтому, що він краще вписується при використанні liftM2, і т.д. також.
ivanm

1
@ L01man люди працювали над цим; див. stackoverflow.com/questions/5730270/… і принаймні для числових класів існують альтернативи: hackage.haskell.org/packages/archive/numeric-prelude/0.3.0.2/…
li.davidm

1
@ L01man Так, це незабаром буде виправлено. Програма Applicative Monad (AMP) виглядає так, що вона перейде в наступну версію Haskell. GHC 7.8.3 має новий прапор, --fwarn-ampякий допоможе оновити існуючий код для переходу.
recursion.ninja
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.