6

Хорошо, это был долгий день, и мой мозг не может функционировать на уровне Haskell, но я просто не могу понять один пример из «Learn You a Haskell».Назначение функции в Haskell

Раздел называется функции приложения с $, и есть пример того, как $ может быть определена:

($) :: (a -> b) -> a -> b 
f $ x = f x 

До сих пор все ясно. Я понимаю, все примеры в разделе, за исключением последнего:

ghci> map ($ 3) [(4+), (10*), (^2), sqrt] 
[7.0,30.0,9.0,1.7320508075688772] 

Здесь мы отображаем ($ 3) по списку функций и получить результат применения этих функций 3. Но как это возможно?

С первого фрагменте кода становится ясно, что первый аргумент функции, мы можем даже написать:

*Main> ($) sqrt 4 
2.0 

Теперь ($ 3) частичное применение функции $, но 3 идет на позиции функция в! Итак, 3 должен быть функцией или что?

Есть еще одна тайна: что это такое: (4+)? Я знаю, что (+4) является частичным применением функции +, поэтому (4+) должно быть частичным применением функции 4? Бред какой то. Какой трюк работает здесь?

+0

Возможный дубликат [Частичное приложение с функциями Infix] (http://stackoverflow.com/questions/10131300/partial-application-with-infix-functions) – Lambdageek

ответ

12

($ 3) и (+ 4) не частичное применение - они секции оператора. Частичное приложение будет выглядеть как (($) 3) или ((+) 4).

Секция оператора вида (? x) (где ? обозначает произвольный оператор инфиксного) связывает правые операнд оператора, т.е. это эквивалентно \y -> y ? x.Аналогично, операторский раздел (x ?) связывает левый операнд и, таким образом, эквивалентно частичному приложению.

6

Я думаю, что вас сбивает разделы оператора. Это позволяет вам частично применять оператор с одним из его аргументов, поэтому вы можете иметь операторы (+4) и (4+), где 4 является вторым, затем первым аргументом + соответственно. Более ярким примером может быть ("Hello" ++) по сравнению с (++ "world"), первый предшествует "Hello" на передней части строки, в то время как последний присоединяет "world" к концу строки.

Это контрастирует с использованием операторов в префиксной форме с помощью только парсеров вокруг него. В этой форме, эквивалентны следующие:

> let join = (++) 
> join "Hello, " "world" 
"Hello, world" 
> (++) "Hello, " "world" 
"Hello, world" 

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


Таким образом, в вашем примере, у вас есть частичное применение ($ 3), вы можете уменьшить его как

map ($ 3) [(4+), (10*), (^2), sqrt] 
[($ 3) (4+), ($ 3) (10 *), ($ 3) (^ 2), ($ 3) sqrt] 
[4 + 3, 10 * 3, 3^2, sqrt 3] 
[7.0, 30.0, 9.0, 1.7320508075688772] 
+0

«вы относитесь к оператору как к нормальной функции», я думал что «операторы» * являются * нормальными функциями в Haskell. – Mark

+1

@Mark они нормальны во всех отношениях, кроме их синтаксиса для приложения. Они по умолчанию являются инфиксами, а функция non operator по умолчанию является префиксом. Когда я говорю о нормальной функции, я имею в виду функцию префикса. – bheklilr

4

Вы получаете путаницу с разделами. Хороший способ понять концепцию секций играют на примере:

(<^>) :: Int -> Float -> Int 
a <^> b = a 

выше функцией является бесполезной функцией, которая возвращает первый параметр независимо от того, что второй параметра. Но он принимает Int, а затем Float в качестве входных данных.

Теперь, из разделов вы можете обратиться с любым из своих аргументов:

λ> let a = (3 <^>) 
λ> :t a 
a :: Float -> Int 
λ> let b = (<^> 3.0) 
λ> :t b 
b :: Int -> Int 

Посмотрите, как тип a и b различны из разделов.

Смежные вопросы