Практическое использование функций карри? - PullRequest
29 голосов
/ 03 февраля 2011

Есть множество обучающих программ о том, как выполнять функции карри, и столько же вопросов здесь, в stackoverflow. Тем не менее, после прочтения «Маленького Schemer», нескольких книг, учебных пособий, сообщений в блогах и потоковых потоков я все еще не знаю ответа на простой вопрос: «Какой смысл в карри?» Я понимаю, как использовать функцию, но не "почему?" за этим.

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

edit: Принимая во внимание некоторые примеры из TLS, в чем выгода

(define (action kind)
    (lambda (a b)
        (kind a b)))

в отличие от

(define (action kind a b)
    (kind a b))

Я вижу только больше кода и никакой дополнительной гибкости ...

Ответы [ 10 ]

24 голосов
/ 03 февраля 2011

Одним из эффективных применений каррируемых функций является уменьшение количества кода.

Рассмотрим три функции, две из которых почти идентичны:

(define (add a b)
  (action + a b))

(define (mul a b)
  (action * a b))

(define (action kind a b)
  (kind a b))

Если ваш код вызывает add,это в свою очередь вызывает action с видом +.То же самое с mul.

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

Все add и sum do, обертывают вызов к action с соответствующим kind.Теперь рассмотрим каррированные определения этих функций:

(define add-curried
  ((curry action) +))

(define mul-curried
  ((curry action) *))

Они стали значительно короче.Мы просто каррировали функцию action, передав ей только один аргумент, kind, и получили функцию карри, которая принимает остальные два аргумента.

Этот подход позволяет вам писать меньше кода с высоким уровнемремонтопригодности.

Только представьте, что функция action будет немедленно переписана, чтобы принять еще 3 аргумента.Без карри вам пришлось бы переписать свои реализации add и mul:

(define (action kind a b c d e)
  (kind a b c d e))

(define (add a b c d e)
  (action + a b c d e))

(define (mul a b c d e)
  (action * a b c d e))

Но карри избавил вас от этой неприятной и подверженной ошибкам работы;вам вообще не нужно переписывать даже символ в функциях add-curried и mul-curried, потому что вызывающая функция предоставит необходимое количество аргументов, переданных action.

11 голосов
/ 03 февраля 2011

Они могут сделать код проще для чтения.Рассмотрим следующие два фрагмента кода Haskell:

lengths :: [[a]] -> [Int]
lengths xs = map length xs

lengths' :: [[a]] -> [Int]
lengths' = map length

Зачем давать имя переменной, которую вы не собираетесь использовать?

Функции с каррированием также помогают в таких ситуациях:1007 *

Удаление этих дополнительных переменных облегчает чтение кода, и вам не нужно мысленно понимать, что такое xs и что такое ys.

HTH.

4 голосов
/ 03 февраля 2011

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

3 голосов
/ 04 февраля 2011

Я думаю, что каррирование - это традиционный способ обработки общих n-арных функций при условии, что единственные, которые вы можете определить, являются унарными.

Например, в лямбда-исчислении (из которого вытекают функциональные языки программирования),есть только абстракции с одной переменной (что переводит в унарные функции в FPL).Что касается лямбда-исчисления, я думаю, что легче доказать вещи о таком формализме, так как на самом деле вам не нужно обрабатывать случай n-арных функций (поскольку вы можете представить любую n-арную функцию с рядом унарных функций посредством каррирования).

(Другие уже рассмотрели некоторые практические последствия этого решения, поэтому я остановлюсь здесь.)

2 голосов
/ 11 мая 2017

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

2 голосов
/ 05 октября 2011

Использование all :: (a -> Bool) -> [a] -> Bool с предикатом карри.

all (`elem` [1,2,3]) [0,3,4,5]

Инфиксные операторы Haskell могут быть каррированы с любой стороны, поэтому вы легко можете каррировать со стороны иглы или контейнера функции elem (is-element-of).

1 голос
/ 09 апреля 2015

Я хотел бы добавить пример к ответу @Francesco.

enter image description here

0 голосов
/ 09 марта 2011

Само по себе карри является синтаксическим сахаром.Синтаксический сахар - это то, что вы хотите сделать легким.C, например, хочет сделать инструкции, которые являются «дешевыми» на ассемблере, такие как инкрементные, простые и поэтому они имеют синтаксический сахар для приращения, нотацию ++.

 t = x + y
 x = x + 1

заменяется на t = x ++ + y

Функциональные языки могут так же легко иметь такие вещи, как.

f(x,y,z) = abc 
g(r,s)(z) = f(r,s,z). 
h(r)(s)(z) = f(r,s,z)

но вместо этого все автоматически.И это позволяет передавать ag, связанный с определенным r0, s0 (т.е. определенными значениями), как функцию с одной переменной.

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

Вы, естественно, захотите использовать сравнениеоператоры (<=>) в Perl и имеют sortordinal = sort (<=>), где sortordinal работает со списками.Чтобы сделать это, вы бы отсортировали функцию карри.
И фактически сортировка списка определена именно так в Perl.

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

0 голосов
/ 03 февраля 2011

Очень легко создавать замыкания.Время от времени я использую SRFI-26.Это действительно мило.

0 голосов
/ 03 февраля 2011

Так что вам не нужно увеличивать шаблон с небольшой лямбдой.

...