Читая М. Липовача "Изучай Haskell во имя добра!", я некоторое время не понимал, чем частичное применение отличается от каррирования. Потратил некоторое время на разбор данного вопроса и набросал себе "шпаргалку" по обозначенной теме.
В Haskell функции без параметров называются определениями (definition) или именами (name).
Функции не могут принимать более одного параметра. Если функция, принимает несколько параметров, то на самом деле она является функцией с одним параметром и возвращает другую функцию, которая так же принимает лишь один параметр и возвращает некоторый результат (др. функцию или конкретное значение).Т.е. если для функции указана такая сигнатура:
то Haskell воспринимает её следующим образом:
Т.е. функция func принимает параметр типа Int и возвращает новую функцию, которая принимает очередной параметр - типа Double и возвращает другую новую функцию, принимающую параметр типа Char и возвращающую значение типа Bool.
Преобразование функции от многих аргументов в функцию, берущую свои аргументы по одному называется каррированием. Haskell автоматически выполняет каррирование всех функций, принимающих более одного параметра. Именно благодаря каррированию становится возможным частичное применение функций, а так же создание сечений. В свою очередь, частичное применение делает возможным существование бесточечной нотации.
Функция uncurry преобразовывает каррированную функцию в некаррированную.
В Haskell функции без параметров называются определениями (definition) или именами (name).
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' = oddghci:
λ: 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"
Комментариев нет:
Отправить комментарий