Каррирование | это... Что такое Каррирование? (original) (raw)
Каррирование или карринг (англ. currying) в информатике — преобразование функции от пары аргументов в функцию, берущую свои аргументы по одному. Это преобразование было введено М. Шейнфинкелем и Г. Фреге и получило свое название в честь Х. Карри.
Содержание
Определение
Для функции h типа h : (A × B) → C оператор каррирования Λ выполняет преобразование Λ(h) : A → (B → C). Таким образом, Λ(h) берет аргумент типа A и возвращает функцию типа B → C. С интуитивной точки зрения, каррирование функции позволяет фиксировать ее некоторый аргумент, возвращая функцию от остальных аргументов. Таким образом, Λ представляет собой функцию типа Λ : (A × B → C) → (A → (B → C)).
Декаррирование вводится как обратное преобразование.
В другом смысле, преобразование ε, противоположное каррированию, восстанавливает каррированный аргумент. Для функции k типа k : A → (B → C) оператор ε типа ε: (U → V) × U → V для произвольных a: A, U = A, V = B → C выполняет преобразование ε[k, a]: B → C. Остаётся положить k = Λ(h), и для ε: (A →(B → C)) × A → (B → C) записываем ε[Λ(h), a]: B → C и ε[k, a] = ε[Λ(h), a], что устанавливает связь между каррированой и некаррированной записью функции[1].
На практике каррирование позволяет рассматривать функцию, которая получила один из аргументов, но не все. Оператор каррирования встроен в некоторые языки программирования, что позволяет многоместные функции приводить к каррированному представлению. Примером служат языки ML и Haskell. Все языки, поддерживающие замыкание, позволяют записывать каррированные функции.
Примеры
C++
Требует наличие библиотек Boost.
#include <boost/function.hpp> #include <boost/lambda/lambda.hpp>
boost::function<int(int)> curry(int a) { return (a + boost::lambda::_1); } int a = curry(4)(5); // 9
Впрочем, в относительно простых (тривиальных) случаях достаточно Стандартной библиотеки С++ (STL).
#include
std::binder1st<std::plus > curry(int a) { return std::bind1st(std::plus(), a); } int a = curry(4)(5); // 9
C++11
auto curry = ([](int x){ return [x](int y) { return x+y; }; }); int a = curry(4)(5); // 9
C# (3.0)
Func<int, Func<int, int>> curry = (x => (y => x + y)); curry(4)(5); // 9
Delphi (2009)
type TIntFunc = reference to function(x: Integer): Integer;
function Curry(x: Integer): TIntFunc; begin Result := function(y: Integer): Integer begin Result := x + y; end; end;
begin Curry(4)(5); // 9 end.
F#
let add a b = a + b //'a -> 'a -> 'a let addOne = add 1 //'a -> 'a let x = addOne 10 // 11
Common Lisp
(defun curry(x) (lambda (y) (+ x y))) ((curry 2) 3) ; вернёт 5 ; из-за особенностей семантики вернет ошибку(в отличие от Scheme)... (funcall (curry 2) 3) ; вернет 5
Haskell
curry x = (\y -> x + y) -- также можно написать curry = (+) curry 2 3 -- вернет 5
Hope
! curry - turn a binary function into a function producing a function. ! (Named after Haskell B. Curry) ! e.g. curry f x y = f(x, y) dec curry : (alpha # beta -> gamma) -> alpha -> beta -> gamma; --- curry f <= lambda x => lambda y => f(x, y); curry (+) 1;
lambda y => 1 + y: num->num (curry (+) 1) 2; 3: num
JavaScript
function curry(x){ return function(y){ return x + y; } } var a = curry(4); a(5); // => 9
Начиная с версии 1.7, появился краткий синтаксис для функций-однострочников и теперь стало возможным писать так:
var curry = function(x) function(y) x+y;
var a = curry(4); a(5); // вернёт 9
Lisp Scheme
; определение (define (curry x) (lambda (y) (+ x y))) ; вызов (let ((curr (curry 4))) (curr 5)) ;результат 9 ; или так ((curry 4) 5)
OCaml
let curry x = function y -> x + y;; (* val curry : int -> int -> int = ) let a = curry 4 5;; ( - : int = 9 *)
OCaml является языком из семейства ML, как писалось выше, в языках этого семейства приведение многоместной функции к каррированному представлению выполняется автоматически. Поэтому можно написать так:
let curry x y = x + y;; (* val curry : int -> int -> int = ) let a = curry 4;; ( val a : int -> int = ) a 5;; ( - : int = 9 *)
Python
curry = lambda x: lambda y: x + y curry(4)(5) # => 9
Perl
sub curry { my $x = shift; return sub { return $x + shift } } curry(4)->(5); # 9
PHP
Работает начиная с PHP 5.3, в котором были добавлены замыкания.[2]
function curry($x) { return function ($y) use ($x) { return x+x + x+y; }; } $a = curry(5); b=b = b=a(10); // 15
Ruby
def curry(x) Proc.new{|y| x + y} end curry(1).call(2) # => 3
Scala
def curry(x:Int)(y:Int) = x + y // curry: (Int)(Int)Int curry(4)(5) // Int = 9
Objective-C
Пример реализации каррирования в Objective-C с использованием блоков(blocks):
typedef int (^Add)(int y);
Add carry(int x) {
return Block_copy(^(int y) {
return x + y;
});
}
int res = carry(5)(6); NSLog(@"%i",res);
11
Google Go
Пример реализации каррирования в Google Go:
package main
func main() { curry := func(x int) func(int) int { return func(y int) int { return x+y } } print(curry(2)(3)) // 5 }
MATLAB
Пример реализации каррирования в MATLAB:
curry = @(x)@(y)x+y;
a = curry(5); disp(a(6)); % 11
Примечания
- ↑ Wolfengagen, V.E. Combinatory logic in programming. Computations with objects through examples and exercises. — 2-nd ed. — M.: «Center JurInfoR» Ltd., 2003. — x+337 с. ISBN 5-89158-101-9.
- ↑ Currying in PHP
См. также
- Переопределение функции