Комментарии 24
В общем, может оказаться полезным в случае работы в группой методов, требующих постоянного проталкивания одних и тех-же параметров. И отличающихся только парочкой.
Хороший пример про логгер, спасибо. Как раз думал над тем, как именно решить эту проблему неуказывания источника.
Насколько я понял принципиальная разница в том, что партиал функция возвращает результат принимая меньше параметров (кешируя дополнительные), а каррированая возвращает функцию, которая возвращает функцию… (повторить n раз)… которая возвращает результат.
Спасибо за перевод.
У меня сразу появилась мысль: а нельзя ли сделать currying или partial function application ещё более универсальными, используя именованные параметры из C# 4.0? То есть, чтобы оба следующих вызова работали одинаково:
Но, наверное, это невозможно.
У меня сразу появилась мысль: а нельзя ли сделать currying или partial function application ещё более универсальными, используя именованные параметры из C# 4.0? То есть, чтобы оба следующих вызова работали одинаково:
curried(a: 1)(b: 2)(c: 3);
curried(c: 3)(b: 2)(a: 1);
Но, наверное, это невозможно.
Это думаю невозможно изза:
Но ведь поменяв порядок аргументов вы получите то же самое(вам не нужны именованые аргументы):
curried(1)(2)(3);
curried(3)(2)(1);
Ведь это ничто иное как:
curried(1) -Ю вернёт объект ссылку на функцию к которой будет применёна параметр (2) и результатом будет опять ссылка на функцию к которой будет применён параметр (3).
return a => b => c => function(a, b, c);
Но ведь поменяв порядок аргументов вы получите то же самое(вам не нужны именованые аргументы):
curried(1)(2)(3);
curried(3)(2)(1);
Ведь это ничто иное как:
curried(1) -Ю вернёт объект ссылку на функцию к которой будет применёна параметр (2) и результатом будет опять ссылка на функцию к которой будет применён параметр (3).
Так вот зачем functools.partial в Python! Спасибо)
По ссылке Jon Skeet Facts порадовал топовый коммент:
Who the hell is Jon Skeet?
Who the hell is Jon Skeet?
частичное применение преобразует функцию с N параметрами в функцию с N-1 параметрами
Если уж быть более формальным то в N-k
Ппц, столько текста, я чуть в транс не ушел…
По поводу (бес)полезности каррирования на практике, в котором сомневается автор.
Скорее всего в C# оно действительно бесполезно, поскольку требует утомительного написания кода и не даёт особых преимуществ. В других языках дело обстоит иначе. Например, в OCaml сама сигнатура функции SampleFunction будет записана как:
Ничего не напоминает? Да, это то же самое «a => b => c => function(a, b, c)», которое пришлось писать руками на C#. То есть, любая объявленная функция получается изначально каррированной, и создание логгера выглядит примерно так:
А вот частичное применение выглядит уже не таким удобным, его ещё надо написать (и оно тоже работает через каррирование):
Согласитесь, совсем не так удобно смотрится.
Скорее всего в C# оно действительно бесполезно, поскольку требует утомительного написания кода и не даёт особых преимуществ. В других языках дело обстоит иначе. Например, в OCaml сама сигнатура функции SampleFunction будет записана как:
val sample_function : int -> int -> int -> string = <fun>
Ничего не напоминает? Да, это то же самое «a => b => c => function(a, b, c)», которое пришлось писать руками на C#. То есть, любая объявленная функция получается изначально каррированной, и создание логгера выглядит примерно так:
(* принимаем на вход имя файла, тип сообщения и сообщение *)
# let logger filename level message = (* здесь логика вывода сообщения в файл *);;
val logger : string -> int -> string -> unit = <fun>
# let business_logger = logger "business.log";; (* Функция, которая принимает уже только два параметра и пишет в лог*)
val business_logger : int -> string -> unit = <fun>
А вот частичное применение выглядит уже не таким удобным, его ещё надо написать (и оно тоже работает через каррирование):
# let partial_apply func x = func x;; (* Функция, которая применяет параметр x в качестве первого параметра *)
val partial_apply : ('a -> 'b) -> 'a -> 'b = <fun>
# let business_logger = partial_apply logger "business.log";;
val business_logger : int -> string -> unit = <fun>
Согласитесь, совсем не так удобно смотрится.
Это всего лишь вопрос обмазанности синтаксическим сахаром того или иного языка. К примеру в языке с нормальной поддержкой частичного применения вполне можно описать случай:
В таких случаях карринг уже не выглядит таким уж удобным.
Напрасно автор статьи выбрал функцию с тремя параметрами, уже на четырех получается гораздо интереснее.
//Фиксируем 1 и 3 параметры
def infoLogger = logger("some.log", _, LogLevel.Info, _);
infoLogger(LogCategory.GUI, "message");
infoLogger(LogCategory.DB, "other message");
В таких случаях карринг уже не выглядит таким уж удобным.
Напрасно автор статьи выбрал функцию с тремя параметрами, уже на четырех получается гораздо интереснее.
Вообще, частичное применение — это тоже карринг. Оба варианта применения функции можно без ошибки называть карированием. fprog.ru/2009/issue3/eugene-kirpichov-elements-of-functional-languages/#currying
Для пущего эффекта можно так же употреблять термин «шейнфинкелинг».
Стоило отметить или где-то добваить, что автор метода — Haskell Brooks Curry, создатель языков Haskell, Brooks и Curry :-)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Карринг vs Частичное применение функции