Немного о каррировании в Haskell
Читая М. Липовача «Изучай Haskell во имя добра!», я поначалу не понимал, чем частичное применение отличается от каррирования. Потратил некоторое время на разбор данного вопроса и набросал себе «шпаргалку» по обозначенной теме.В Haskell функции без параметров называются константными функциями, поскольку каждая из них всегда возвращает одно и то же значение. func: String func = «Haskell» Функции не могут принимать более одного параметра. Если функция, принимает несколько параметров, то на самом деле она является функцией с одним параметром и возвращает другую функцию, которая так же принимает лишь один параметр и возвращает некоторый результат (др. функцию или конкретное значение).Т.е. если для функции указана такая сигнатура: func: Int → Double → Char → Bool то Haskell воспринимает её следующим образом: func: Int → (Double → (Char → Bool)) Т.е. функция func принимает параметр типа Int и возвращает новую функцию, которая принимает очередной параметр — типа Double и возвращает другую новую функцию, принимающую параметр типа Char и возвращающую значение типа Bool.Преобразование функции от многих аргументов в функцию, берущую свои аргументы по одному называется каррированием. Haskell автоматически выполняет каррирование всех функций, принимающих более одного параметра. Именно благодаря каррированию становится возможным частичное применение функций, а так же создание сечений. В свою очередь, частичное применение делает возможным существование бесточечной нотации.Примечание В Haskell не существует такого понятия, как частичное применение функции. Существует применение функции (без «частично»). Если мы говорим (для удобства восприятия), что функция f: Int → Int → Int имеет два аргумента, (что с технической точки зрения не является корректным), то мы можем так же сказать (снова для удобства восприятия), что f 5 — это частично применённая функция (что так же не будет корректно технически).
Пример func: (Num a) => a → a → a → a func a b c d = a + b + c + d ghci Частичное применение: λ: let n = func 2 3 λ: let m = n 10 λ: let g = m 7 λ: g 22 Сечения: λ: let a = (/2) λ: a 10 5.0 λ: let b = (15/) λ: b 5 3.0 Бесточечная нотация: odd' :: Integral a => a → Bool odd' = odd ghci: λ: odd' 5 True λ: odd' 4 False Каррирование и декаррирование В стандартном модуле Data.Tuple определены, помимо прочего, следующие функции: curry: ((a, b) → c) → a → b → c uncurry: (a → b → c) → (a, b) → c Функция curry преобразовывает некаррированную функцию в каррированную.Функция uncurry преобразовывает каррированную функцию в некаррированную.Пример msg: Int → Bool → String msg n True = show $ n `div` 2 msg n _ = show $ n * 2 ghci λ: let n = msg λ: let m = uncurry n λ: : t n n: Int → Bool → String λ: : t m m: (Int, Bool) → String λ: n 5 True »2» λ: m (5, True) »2» λ: let k = curry m λ: : t k k: Int → Bool → String λ: k 5 True »2»