Вопрос

Некоторое время назад я спросил вопрос про $, и получил полезные ответы — на самом деле, мне казалось, что я понял, как его использовать.

Кажется я ошибся :(

Этот пример показан в учебнике:

instance Monad [] where
   xs >>= f = concat . map f $ xs

Я не могу хоть убей понять, почему там использовался $;ghci мне тоже не помогает, поскольку даже тесты, которые я там провожу, похоже, показывают эквивалентность версии, в которой просто опускается $.Может ли кто-нибудь прояснить это для меня?

Это было полезно?

Решение

Здесь используется $ , поскольку он имеет более низкий приоритет, чем обычное применение функции. Другой способ написать этот код выглядит так:

instance Monad [] where
   xs >>= f = (concat . map f) xs

Идея заключается в том, чтобы сначала создать функцию ( concat. map f ), а затем применить ее к своему аргументу ( xs ). Как показано, это также можно сделать, просто поместив скобки вокруг первой части.

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

instance Monad [] where
  xs >>= f = concat . (map f xs)

Что не имеет смысла, потому что второй аргумент оператора композиции функций вообще не является функцией. Хотя следующее определение имеет смысл:

instance Monad [] where
  xs >>= f = concat (map f xs)

Кстати, это тоже определение, которое я бы предпочел, потому что мне кажется, что оно намного понятнее.

Другие советы

Я хотел бы объяснить, почему ИМХО это не используемый стиль:

instance Monad [] where
  xs >>= f = concat (map f xs)

concat. карта f является примером так называемой записи в стиле pointfree; где pointfree означает «без точки приложения». Помните, что в математике в выражении y = f (x) мы говорим, что f применяется к точке x . В большинстве случаев вы можете сделать последний шаг, заменив:

f x = something $ x

с

f = something

как f = concat. карта f , и это на самом деле стиль без точек. То, что яснее, является спорным, но стиль pointfree дает другую точку зрения, которая также полезна, поэтому иногда используется, даже когда она не совсем нужна.

РЕДАКТИРОВАТЬ: я заменил бессмысленно на pointfree и исправил некоторые примеры после комментария Alasdair, которого я должен поблагодарить.

Причина, по которой здесь используется $, связана с сигнатурой типа (.):

(.) :: (b -> c) -> (a -> c) -> a -> c

Здесь у нас есть

map f :: [a] -> [[b]]

и

concat :: [[b]] -> [b]

Итак, мы получаем

concat . map f :: [a] -> [b]

а тип (.) можно записать как

(.) ::([[b]] ​​-> [b]) -> ([a] -> [[b]]) -> [a] -> [b]

Если бы мы использовали concat . map f xs, мы бы это увидели

map f xs :: [[b]]

Поэтому его нельзя использовать с (.).(тип должен быть (.) ::(а -> б) -> а -> б

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top