Что на самом деле делает $ function в haskell?

Я знаю

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

Интуитивно, мне кажется, как бы сказать: 1. $ задерживает оценку функции слева 2. оценивает то, что справа 3. передает результат слева направо.

И это имеет смысл для меня, когда,

ghci> length $ [1..5]
5
ghci> ($) length [1..5]
5

То, что я не понимаю, это почему,

ghci> ($ [1..5]) length
5

Судя по типу $, разве этот (первый) аргумент не должен быть функцией?

3 ответа

Решение

Это связано с разбором. В Haskell вы можете написать (op arg) где op является инфиксным оператором Это не то же самое, что ((op) arg), И ты можешь написать (arg op) также! Например:

GHCi, version 7.0.3: http://www.haskell.org/ghc/  :? for help
Prelude> :t (+ 4)
(+ 4) :: Num a => a -> a
Prelude> :t (4 +)
(4 +) :: Num a => a -> a

То есть, (+ 4) это функция \x -> x + 4 а также (4 +) это функция \y -> 4 + y, В случае сложения это равные функции, но это сейчас не очень важно.

Теперь давайте попробуем тот же трюк на $:

Prelude> :t ($ [1,2,3,4])
($ [1,2,3,4]) :: Num t => ([t] -> b) -> b

Теперь сюрприз, мы получили \f -> f $ [1,2,3,4], Мы также можем написать

Prelude> :t (length $)
(length $) :: [a] -> Int

чтобы получить функцию \l -> length $ l, Но как насчет этого:

Prelude> :t ($ length)
($ length) :: (([a] -> Int) -> b) -> b

Это странно, но имеет смысл! У нас есть \f -> f $ lengthфункционал, который ожидает получить функцию f типа ([a] -> Int) -> b) это будет применяться к length, Существует четвертая возможность:

Prelude> :t ([1,2,3,4] $)

<interactive>:1:2:
    Couldn't match expected type `a0 -> b0' with actual type `[t0]'
    In the first argument of `($)', namely `[1, 2, 3, 4]'
    In the expression: ([1, 2, 3, 4] $)

Все так и должно быть, потому что [1,2,3,4] это не функция. Что если мы напишем $ в скобках? Тогда его особое значение как инфиксного оператора исчезает:

Prelude> :t (($) length)
(($) length) :: [a] -> Int

Prelude> :t (($) [1,2,3,4])
<interactive>:1:6:
    Couldn't match expected type `a0 -> b0' with actual type `[t0]'
    In the first argument of `($)', namely `[1, 2, 3, 4]'
    In the expression: (($) [1, 2, 3, 4])

Prelude> :t (length ($))
<interactive>:1:9:
    Couldn't match expected type `[a0]'
                with actual type `(a1 -> b0) -> a1 -> b0'
    In the first argument of `length', namely `($)'
    In the expression: (length ($))

Prelude> :t ([1,2,3,4] ($))
<interactive>:1:2:
    The function `[1, 2, 3, 4]' is applied to one argument,
    but its type `[t0]' has none
    In the expression: ([1, 2, 3, 4] ($))

Итак, чтобы ответить на ваш вопрос: $ [1,2,3,4] анализируется как \f -> f $ [1,2,3,4] так что имеет смысл применить его к length, тем не мение ($) [1, 2, 3, 4] не имеет большого смысла, потому что ($) не рассматривается как инфиксный оператор.

Кстати, $ "ничего не делает", так сказать. Он в основном используется для более удобочитаемого ввода, потому что он имеет низкий приоритет и поэтому мы можем написать f $ g $ h $ x вместо f (g (h x)),

Ваш вопрос действительно о том, что называется разделами оператора. С любым оператором в Haskell (я буду использовать + в качестве примера) можно написать что-то вроде (+ arg) или же (arg +), Это просто сокращенный синтаксис для анонимных функций (\x -> x + arg) а также (\x -> arg + x)соответственно.

Итак ($ [1..5]) синтаксис просто означает (\x -> x $ [1..5]) который так же, как (\x -> x [1..5]) (т.е. функция, которая проходит [1..5] функции, переданной в качестве аргумента).

($ [1..5]) это раздел. Это частично применяемый оператор. Это сокращение для (\f -> f $ [1..5]),

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

Взгляните на http://www.haskell.org/haskellwiki/Section_of_an_infix_operator

Другие вопросы по тегам