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

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

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

f = g . h

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

k = a $ b $ c $ value

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

k = a . b . c $ value

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

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

Ответ 1

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

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

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

Ответ 2

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

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

и

k = (a . b . c) value

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

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

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

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

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