12

Хотя я немного понимаю о каррировании в математическом смысле, частично , применяя функцию инфикса, была новая концепция, которую я обнаружил после погружения в книгу Learn You a Haskell for Great Good.Частичное применение с функциями Infix

Учитывая эту функцию:

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? Является ли он универсальным для всех функций infix?


Как примечание стороны, это моя первая неделя с Haskell и функциональным программированием, и я до сих пор читаю книгу.

ответ

18

Да, вы можете частично применить оператор инфикса, указав либо его левый, либо правый операнд, просто оставив пустой пробел (точно в двух приведенных вами примерах).

Так, ([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 
+0

Так что, я не знаю Haskell, но '(1 \' Элем \ '') так же, как '1' элем? – Neil

+1

@Neil: Да, это так. –

+4

Мне нравится думать о '(++)' как о разделе, в котором вы опускаете оба входа. –

5

Все операторы инфиксных может быть использован в разделы в Haskell - за исключением - из-за странности с унарным отрицанием. Это даже включает функции без инфикса, преобразованные в infix с использованием обратных ссылок. Вы можете даже думать о композиции для изготовления операторов в нормальные функции в двухстороннем разделе:

(x + y) ->(+ y) ->(+)

секция (в основном, с некоторыми редкими случаями угловых) рассматривались как простые лямбды. (/ 2) таких же, как:

\x -> (x/2)

(2 /) и такой же, как \x -> (2/x), для примера с некоммутативномом оператором.

Здесь ничего интересного теоретически не происходит. Это просто синтаксический сахар для частичного применения инфиксных операторов. Это делает код немного красивее, часто. (Конечно, есть контрпримеры.)

+2

Обратите внимание, что «странность с унарным отрицанием» объясняется тем, что неоднозначно, следует ли интерпретировать '(- 1)' как числовой литерал -1 или как функцию '\ x -> x - 1'. Выбор создателей Haskell состоял в том, чтобы интерпретировать его как числовой литерал и предоставить функцию 'subtract', которая удовлетворяет' subtract x = \ y -> y - x'. Они также обеспечивают «отрицание», которое действует как унарная минусовая функция, то есть «отрицать x = -x» –

+0

@ ChrisTaylor: почти. '(- x)' преобразуется в 'negate x', поэтому' (- 1) 'is' negate (fromInteger 1) ', а не' fromInteger (-1) '. Разумеется, они должны быть эквивалентны для корректных экземпляров «Num». – hammar

+0

@hammar Ах, ладно, немного логики назад. Спасибо за исправление! –

15

Да, это the section syntax на работе.

Разделы написаны как (op e) или (e op), где op - бинарный оператор, а e - выражение. Разделы являются удобным синтаксисом для частичного применения бинарных операторов.

следующие тождества:

(op e) = \ x -> x op e 
(e op) = \ x -> e op x 
Смежные вопросы