Трохи про каррировании в 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
λ: нехай g = m 7
λ: g
22

Перерізу:
λ: let a = (/2)
λ: a 10
5.0
λ: нехай 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 = n uncurry
λ: :t n
n :: Int -> Bool -> String
λ: :t m
m :: (Int, Bool) -> String
λ: n 5 True
"2"
λ: m (5,True)
"2"
λ: let k = m curry
λ: :t k
k :: Int -> Bool -> String
λ: k 5 True
"2"


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.