Путаница с композицией функций в Haskell - PullRequest
4 голосов
/ 02 августа 2011

Рассмотрим следующее определение функции в ghci.

let myF = sin . cos . sum 

где. обозначает композицию двух функций (справа ассоциативно). Это я могу назвать

myF [3.14, 3.14]

и это дает мне желаемый результат. По-видимому, он передает список [3.14, 3.14] в функцию 'sum', а его 'результат' передается в cos и так далее и так далее. Однако, если я сделаю это в интерпретаторе

let myF y = sin . cos . sum y 

или

let myF y = sin . cos (sum y) 

тогда у меня возникают проблемы. Изменение этого в следующее дает мне желаемый результат.

let myF y = sin . cos $ sum y 

или

let myF y = sin . cos . sum $ y 

Тип (.) Говорит о том, что не должно быть проблем со следующей формой, поскольку 'sum y' также является функцией (не так ли? Ведь в Haskell все есть функция?)

let myF y = sin . cos . sum y -- this should work?

Что более интересно, я могу заставить его работать с двумя (или многими) аргументами (представьте, что список рассылки [3.14, 3.14] является двумя аргументами x и y), я должен написать следующее

let (myF x) y = (sin . cos . (+ x)) y 
myF 3.14 3.14 -- it works! 
let myF = sin . cos . (+) 
myF 3.14 3.14 -- -- Doesn't work!

На HaskellWiki обсуждается эта форма, которую они называют «PointFree» http://www.haskell.org/haskellwiki/Pointfree. Читая эту статью, я подозреваю, что эта форма отличается от композиции двух лямбда-выражений. Я запутываюсь, когда пытаюсь нарисовать линию, разделяющую оба эти стиля.

Ответы [ 3 ]

9 голосов
/ 02 августа 2011

Давайте посмотрим на типы .Для sin и cos имеем:

cos, sin :: Floating a => a -> a

Для sum:

sum :: Num a => [a] -> a

Теперь sum y превращает это в

sum y :: Num a => a

это значение, а не функция (вы можете назвать ее функцией без аргументов, но это очень сложно, и вам также нужно назвать () -> a функции - где-то было обсуждение этого, но я не могу найтиссылка теперь - Конал говорил об этом).

В любом случае, попытка cos . sum y не будет работать, потому что . ожидает, что обе стороны будут иметь типы a -> b и b -> c (подпись (b -> c) -> (a -> b) -> (a -> c)) и sum y не могут быть написаны в этом стиле.Вот почему вам нужно включить скобки или $.

Что касается стиля без точек, простой рецепт перевода таков:

  • возьмет вас в действие и переместит последний аргументФункция до конца выражения, разделенная приложением функции.Например, в случае mysum x y = x + y у нас есть y в конце, но мы не можем удалить его прямо сейчас.Вместо этого, переписав как mysum x y = (x +) y, он работает.
  • удалить указанный аргумент.В нашем случае mysum x = (x +)
  • повторять до тех пор, пока у вас не останется больше аргументов.Здесь mysum = (+)

(я выбрал простой пример, для более запутанных случаев вам придется использовать flip и другие)

6 голосов
/ 02 августа 2011

Нет, sum y не является функцией.Это число, как и sum [1, 2, 3].Поэтому вполне понятно, что вы не можете использовать оператор компоновки функций (.) с ним.

Не все в Haskell являются функциями.

3 голосов
/ 03 августа 2011

Обязательный загадочный ответ таков: (пробел) связывает более тесно, чем .

Большинство пробелов в Haskell можно рассматривать как очень высокую степень исправления $ (функция «apply»). w x . y z в основном совпадает с (w $ x) . (y $ z)

Когда вы впервые узнаете о $ и ., вам также следует убедиться, что вы также узнали о (пробел), и убедиться, что вы понимаете, как семантика языка неявно заключает в скобки вещи таким образом, что (на первый взгляд) кажутся интуитивно понятными.

...