Частичное применение с инфиксными функциями
В то время как я немного понимаю о карри в математическом смысле, частичное применение инфиксной функции было новой концепцией, которую я открыл после того, как окунулся в книгу " Изучите вас на хаскеле для великого добра".
Учитывая эту функцию:
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
Автор использует это интересным способом:
ghci> applyTwice (++ [0]) [1]
[1,0,0]
ghci> applyTwice ([0] ++) [1]
[0,0,1]
Здесь я ясно вижу, что полученная функция имела различные параметры, которые не были бы получены обычными средствами, учитывая, что это функция с карри (не так ли?). Итак, есть ли какой-то особый подход к разделу инфиксов от Haskell? Это универсально для всех инфиксных функций?
Как примечание, это моя первая неделя с Haskell и функциональным программированием, и я все еще читаю книгу.
3 ответа
Да, вы можете частично применить инфиксный оператор, указав его левый или правый операнд, просто оставив другой пустой (точно в двух написанных вами примерах).
Так, ([0] ++)
такой же как (++) [0]
или же \x -> [0] ++ x
(помните, что вы можете превратить инфиксный оператор в стандартную функцию с помощью скобок), в то время как (++ [0])
равно \x -> x ++ [0]
,
Также полезно знать об использовании обратных галочек ( ``), которые позволяют превратить любую стандартную функцию с двумя аргументами в инфиксном операторе:
Prelude> elem 2 [1,2,3]
True
Prelude> 2 `elem` [1,2,3] -- this is the same as before
True
Prelude> let f = (`elem` [1,2,3]) -- partial application, second operand
Prelude> f 1
True
Prelude> f 4
False
Prelude> let g = (1 `elem`) -- partial application, first operand
Prelude> g [1,2]
True
Prelude> g [2,3]
False
Да, это синтаксис раздела на работе.
Разделы написаны как ( op e )
или же ( e op )
где op - бинарный оператор, а e - выражение. Разделы - это удобный синтаксис для частичного применения бинарных операторов.
Следующие тождества имеют место:
(op e) = \ x -> x op e
(e op) = \ x -> e op x
Все инфиксные операторы могут использоваться в разделах в Haskell - кроме -
из-за странности с одинарным отрицанием. Это даже включает неинфиксные функции, преобразованные в инфикс с помощью обратных тиков. Вы даже можете думать о формулировке для превращения операторов в обычные функции как двухсторонний раздел:
(x + y)
->(+ y)
->(+)
Разделы (в основном, с некоторыми редкими угловыми случаями) рассматриваются как простые лямбды. (/ 2)
такой же как:
\x -> (x / 2)
а также (2 /)
такой же как \x -> (2 / x)
для примера с некоммутативным оператором.
Там нет ничего глубоко интересного теоретически здесь происходит. Это просто синтаксический сахар для частичного применения инфиксных операторов. Это делает код немного красивее, часто. (Есть контрпримеры, конечно.)