Вы, вероятно, получил ответ на свой вопрос уже, но только повторить:
Если мы имеем
add x y = x + y
, то можно сказать следующее:
add = \ x y -> x + y
add 3 = \ y -> 3 + y
add 3 5 = 3 + 5 = 8
Вы спрашиваете «как можно max 3
вычислить что-нибудь? », и ответ« это не может ». Он просто дает вам еще одну функцию . Эта функция может что-то сделать, когда вы ее вызываете, но вы не «получите ответ» как таковой до все аргументы были предоставлены. До тех пор вы просто получаете функции.
В большинстве случаев это просто полезный синтаксический ярлык. Например, вы можете написать
uppercase :: String -> String
uppercase = map toUpper
вместо того, чтобы сказать
uppercase xs = map toUpper xs
Обратите внимание, что если map
были свои аргументы наоборот, мы не смогли бы сделать это (вы можете только проведите последний аргумент, а не _first), поэтому может быть важно подумать о том, какой порядок вы определяете аргументами своих функций.
Я говорю «большую часть времени», потому что это больше, чем синтаксический сахар.Есть несколько мест на языке, где вы можете обрабатывать функции с различным числом аргументов полиморфно из-за currying. Каждая функция возвращает ответ или другую функцию. Если вы думаете об этом как о связанном списке (который либо содержит следующий элемент данных, либо маркер конца списка), вы можете увидеть, как это позволяет рекурсивно обрабатывать функции.
Итак, что же я подразумеваю под этим? Например, QuickCheck может тестировать функции с любым количеством аргументов (при условии, что есть возможность автоматически генерировать тестовые данные для каждого аргумента). Это возможно, потому что типы функций являются точеными. Каждая функция возвращает либо другую функцию, либо результат. Если вы думаете об этом как о связанном списке, вы можете представить QuickCheck, рекурсивно повторяя функцию, пока не останется больше аргументов.
Следующий фрагмент кода может или не может объяснить идею:
class Arbitrary a where
autogenerate :: RandomGenerator -> a
instance Arbitrary Int
instance Arbitrary Char
...
class Testable t where
test t :: RandomGenerator -> Bool
instance Testable Bool where
test rnd b = b
instance (Arbitrary a, Testable t) => Testable (a -> t) where
test rnd f = test $ f (autogenerate rnd)
Если мы имеем функцию foo :: Int -> Int -> Bool
, то это Testable
. Зачем? Хорошо, Bool
можно проверить, поэтому так Int -> Bool
, и поэтому так Int -> (Int -> Bool)
.
Напротив, каждый размер кортежа отличается от другого, поэтому вам нужно написать отдельные функции (или экземпляры) для каждого размера кортежа. Вы не можете рекурсивно обрабатывать кортежи, потому что они не имеют рекурсивной структуры.
См. Также [В чем преимущество каррирования?] (Http://programmers.stackexchange.com/q/185585/61231). –
Я думаю, что этот вопрос и мой ответ там могут помочь: http://stackoverflow.com/questions/8148253/how-are-functions-curried/8148957 – Ben