#haskell
#haskell
Вопрос:
Я заметил, что некоторые имена функций заканчиваются на _
in Haskell (например mapM_
, traverse_
).
Что это значит?
Комментарии:
1. Вы имеете в виду, например
traverse_
,mapM_
, и т.д.?2. Это кратко упоминается в разделе «соглашения об именах» здесь: hackage.haskell.org/package/base-4.12.0.0/docs/… По сути, это используется для обозначения того, что «результат» монадического значения / действия игнорируется, а действие используется исключительно из-за его «побочных эффектов». (Кавычки, потому что это строго верно только для ввода-вывода, где, я думаю, различие легче понять — для других, «чистых» монад / аппликативов, это скорее аналогия.)
3. @RobinZigmond Я бы назвал это не столько аналогией, сколько обобщением. Это означает «за его прикладные эффекты», где для ИО этот эффект часто называют побочным эффектом.
Ответ №1:
Это просто соглашение об именовании в Прелюдии. Как правило, функции без подчеркивания (например traverse
, sequence
, mapM
) возвращают некоторое значимое «совокупное» значение, тогда как аналоги с подчеркиванием (например traverse_
, sequence_
, mapM_
) возвращают ()
. Обычно вы используете первый набор функций, но если вас не волнует возвращаемое значение, то вы бы использовали второй набор функций. Причина этого в том, что эти функции обычно являются монадическими; если вы используете функцию, возвращаемую ()
в монадическом контексте, но игнорируете возвращаемое значение, GHC не выдает предупреждения (поскольку оно всегда будет возвращаться ()
), но GHC предупреждает вас, если функция выдает значимое возвращаемое значение, которое вы игнорируете. Так что, например do { sequence [print 1,print 2,print 3]; putStrLn "ignoring prev value" }
, выдаст предупреждение, но do { sequence_ [print 1,print 2,print 3]; putStrLn "ignoring prev value" }
не выдаст.
Комментарии:
1. Возврат
()
также иногда «проще».traverse_
, например, требуется толькоFoldable
коллекция, потому что коллекцию не нужно перестраивать в новом контексте, даже еслиtraverse
требуетсяTraversable
.2. Это также может оказать существенное влияние на производительность.
traverse
должен удерживать фрагменты, необходимые для построения результата, в то времяtraverse_
как может просто выбросить их по ходу дела.