Идиомы композиции функций (.) И приложения функции ($) в Haskell: правильное использование

Я читал Real World Haskell и близок к концу, но вопрос стиля не давал мне покончить с операторами (.) и ($).

Когда вы пишете функцию, которая является композицией других функций, вы пишете ее так:

f = g . h

Но когда вы применяете что-то в конце этих функций, я пишу это так:

k = a $ b $ c $ value

Но книга написала бы это так:

k = a . b . c $ value

Теперь, для меня они выглядят функционально эквивалентными, они делают то же самое в моих глазах. Однако чем больше я смотрю, тем больше я вижу людей, которые пишут свои функции так, как это делает книга: сначала составьте с помощью (.), а затем только в конце используйте ($), чтобы добавить значение для оценки партии (никто не делает это с большим количеством долларов. композиции).

Есть ли причина использовать книжный способ, который намного лучше, чем использование всех ($) символов? Или здесь есть какая-то передовая практика, которую я не понимаю? Или это лишнее, и я не должен об этом вообще беспокоиться?


person Robert Massaioli    schedule 13.06.2010    source источник
comment
Обратите внимание, что второй пример может быть выполнен как k = a $ b $ c value   -  person Thomas Eding    schedule 13.06.2010
comment
Да, может, как упоминал Зифре ниже, но я решил оставить это там, так как это ничему не вредит и делает его (а теперь и ваши) комментарии осмысленными. Однако, спасибо. +1 :)   -  person Robert Massaioli    schedule 14.06.2010
comment
Другой распространенный подход - a . b $ c value, который мне не нравится так сильно, как третий пример, но он сохраняет несколько символов.   -  person John L    schedule 20.06.2012


Ответы (7)


Думаю, я могу ответить на этот вопрос авторитетно.

Есть ли причина использовать книжный способ, который намного лучше, чем использование всех символов ($)?

Нет особой причины. Мы с Брайаном предпочитаем уменьшать линейный шум. . тише, чем $. В результате в книге используется синтаксис f . g . h $ x.

person Don Stewart    schedule 13.06.2010
comment
Что ж, я не могу надеяться на лучший ответ, чем этот; от самого автора. :) И в этом есть смысл, когда я читаю, на странице действительно намного тише. Отметьте это как ответ, потому что он напрямую отвечает на вопрос. Спасибо за ответ; и, по сути, книга. - person Robert Massaioli; 13.06.2010
comment
Не хочу не соглашаться с автором, но я думаю, что есть еще одна более заметная причина в ментальной модели создания чего-либо, а не использования этого. Пользователи Haskell склонны думать о f.g.h как о новом умном творении, а не f(g(h())). Теперь они вызывают новую, хотя и анонимную, функцию, которую они создали, а не просто связывают в цепочку большой словарь готовых вызовов функций, как пользователь PHP. - person Evan Carroll; 22.06.2010
comment
Это интересное утверждение: «уменьшить линейный шум» и «тише, чем». Я никогда не думал о языках программирования в этой терминологии, но это имеет смысл. - person Rabarberski; 27.05.2013

Они действительно эквивалентны: имейте в виду, что оператор $, по сути, ничего не делает. f $ x оценивается как f x. Целью $ является его фиксированное поведение: правоассоциативный и минимальный приоритет. После удаления $ и использования скобок для группировки вместо приоритета инфиксов фрагменты кода выглядят следующим образом:

k = a (b (c (value)))

а также

k = (a . b . c) value

Причина предпочтения версии . версии $ - та же причина, по которой предпочтение было отдано обоим версиям, заключенным в скобки выше: эстетическая привлекательность.

Хотя некоторые могут задаться вопросом, основано ли использование инфиксных операторов вместо круглых скобок на каком-то подсознательном стремлении избежать любого возможного сходства с Лиспом (шучу ... я думаю?).

person C. A. McCann    schedule 13.06.2010

Я бы добавил, что в f . g $ x f . g - это значимая синтаксическая единица.

Между тем, в f $ g $ x f $ g не имеет смысла. Цепочка $, возможно, более обязательна - сначала получить результат g из x, затем выполнить f с ним, затем сделать foo, чтобы это, затем и т. д.

Между тем, цепочка ., возможно, более декларативна и в некотором смысле ближе к представлению, ориентированному на потоки данных - составляет ряд функций и в конечном итоге применяет их к чему-то.

person sclv    schedule 22.06.2010
comment
Я изучаю Haskell (ничего значимого не написал), но мне нравится думать о $ как о своего рода операторе канала. Это очень похоже на терминал | pipe (кроме потоков данных справа налево), но, как и в терминальных процессах, каждая единица явно независима. - person LostSalad; 24.06.2014
comment
Оператор $, похоже, ведет себя аналогично оператору <| в F #. Я считаю, что на самом деле оба они определены одинаково - в F # (<|) a b = a b и в Haskell a $ b = a b, которые по сути эквивалентны. - person Tom Galvin; 17.03.2015
comment
@Quackmatic Достаточно уверен, что это (<|) b a = a b в F #, поскольку он используется как [1; 2; 3; 4; 5] <| List.map ((+) 1), если память не изменяет. - person BalinKingOfMoria Reinstate CMs; 20.02.2016
comment
@BalinKingOfMoria Оператор <| передает значение функции, а не передает функцию в значение - вместо этого ваш пример кода будет работать с оператором |>. - person Tom Galvin; 22.02.2016
comment
@Quackmatic Ой. Не знал, что существует несколько версий (я не очень много использовал F #). - person BalinKingOfMoria Reinstate CMs; 22.02.2016
comment
Отличное различие, вы выразили то, что у меня было интуитивным чутьем. - person ThomasH; 16.08.2016

Для меня, я думаю, ответ - (а) аккуратность, поскольку Дон сказал; и (b) я обнаружил, что когда я редактирую код, моя функция может закончиться безточечным стилем, и тогда все, что мне нужно сделать, это удалить последний $ вместо того, чтобы вернуться и изменить все. Мелочь, конечно, но тонкость.

person Antal Spector-Zabusky    schedule 13.06.2010
comment
Да, это хорошая причина написать это так, если вы хотите закончить композицией функций, тогда это будет быстрее. :) Ура за экономию нажатий клавиш, но главное время. +1 - person Robert Massaioli; 13.06.2010

Есть интересное обсуждение этого вопроса в этой ветке haskell-cafe . По-видимому, существует точка зрения меньшинства, согласно которой правая ассоциативность $ - это " просто неправильно ", и выбор f . g . h $ x вместо f $ g $ h $ x - один из способов обойти эту проблему.

person Travis Brown    schedule 13.06.2010
comment
Эй, вы нашли целую дискуссию по этому поводу. Это потрясающе, я сейчас читаю. +1 - person Robert Massaioli; 14.06.2010
comment
Аналогичные аргументы здесь: ghc.haskell.org/trac/haskell-prime/wiki/ - person enrique; 26.12.2014
comment
Обратите внимание, что $! также имеет совершенно неправильную правильную ассоциативность - Почему $! оператор правоассоциативный?. - person imz -- Ivan Zakharyaschev; 07.07.2015

Это просто вопрос стиля. Однако то, как это написано в книге, имеет для меня больше смысла. Он объединяет все функции, а затем применяет их к значению.

Ваш метод выглядит странно, а последний $ не нужен.

Однако на самом деле это не имеет значения. В Haskell обычно есть много-много правильных способов сделать то же самое.

person Zifre    schedule 13.06.2010
comment
Я не заметил, что последний доллар не нужен, но я должен был это сделать. Спасибо, и я оставлю это там, чтобы люди знали, что означает этот комментарий. - person Robert Massaioli; 13.06.2010

Я понимаю, что это очень старый вопрос, но я думаю, что есть еще одна причина, о которой не упоминалось.

Если вы объявляете новую функцию без точек f . g . h, значение, которое вы передаете, будет применено автоматически. Однако, если вы напишете f $ g $ h, это не сработает.

Я думаю, что причина, по которой автор предпочитает метод композиции, заключается в том, что он приводит к хорошей практике построения функций.

person hackeryarn    schedule 12.09.2015