고차 함수
Higher-order function수학과 컴퓨터 과학에서 고차 함수(HOF)는 다음 중 적어도 하나를 수행하는 함수입니다.
다른 모든 함수는 1차 함수입니다.수학에서는 고차 함수를 연산자 또는 함수라고도 합니다.미적분학에서 미분 연산자는 함수를 도함수, 또한 함수에 매핑하기 때문에 일반적인 예입니다.고차 함수는 수학 전반에 걸쳐 "함수"라는 단어의 다른 용도와 혼동해서는 안 됩니다. 함수(동음이의)를 참조하십시오.
비유형 람다 미적분에서는 모든 함수가 고차입니다.대부분의 함수 프로그래밍 언어가 파생된 유형 람다 미적분에서는 하나의 함수를 인수로 사용하는 고차 함수는 형식의값입니다.( 1 2 ) \ displaystyle ( \ _ { \ to \ { 2} \ _)
일반적인 예
map
함수(function)는 많은 함수 프로그래밍 언어에서 볼 수 있는 고차 함수의 한 예입니다.인수로서 함수 f와 요소의 컬렉션을 사용하고, 그 결과 컬렉션의 각 요소에 f가 적용된 새로운 컬렉션을 반환합니다.- 정렬 함수 - 비교 함수를 매개 변수로 사용하여 프로그래머가 정렬되는 항목의 비교에서 정렬 알고리즘을 분리할 수 있습니다.C 표준 함수
qsort
예를 들어 보겠습니다. - 필터
- 접다
- 적용합니다.
- 기능구성
- 통합
- 콜백
- 트리 트래버설
- 자연어의 의미론인 몬태규 문법은 고차 함수를 사용한다
프로그래밍 언어 지원
직접 지원
이 예제는 프로그래밍 언어를 비교 및 대조하기 위한 것이 아니라 고차 함수 구문의 예로서 기능합니다.
다음 예제에서는 고차 함수가twice
함수를 가져와서 함수를 특정 값에 두 번 적용합니다.한다면twice
여러 번 적용해야 합니다.f
값이 아닌 함수를 반환하는 것이 바람직합니다.이는 '반복하지 말라'는 원칙과 일치한다.
APL
두번이라.←{⍺⍺ ⍺⍺ ⍵} 플라스틱←{⍵+3} g←{플라스틱 두번이라. ⍵} g 7 13
또는 암묵적인 방식으로:
두번이라.←⍣2 플라스틱←+∘3 g←플라스틱 두번이라. g 7 13
C++
사용.std::function
C++11:
#실패하다 <iostream> #실패하다 <기능> 자동 두번이라. = [](컨스턴트 표준::기능.< >인트(인트)>& f) { 돌아가다 [&f](인트 x) { 돌아가다 f(f(x)); }; }; 자동 플러스_3 = [](인트 i) { 돌아가다 i + 3; }; 인트 주된() { 자동 g = 두번이라.(플러스_3); 표준::외치다 << > g(7) << > '\n'; // 13 }
또는 C++14에서 제공하는 일반 람다를 사용하는 경우:
#실패하다 <iostream> 자동 두번이라. = [](컨스턴트 자동& f) { 돌아가다 [&f](인트 x) { 돌아가다 f(f(x)); }; }; 자동 플러스_3 = [](인트 i) { 돌아가다 i + 3; }; 인트 주된() { 자동 g = 두번이라.(플러스_3); 표준::외치다 << > g(7) << > '\n'; // 13 }
C#
딜러만 사용하는 경우:
사용. 시스템.; 일반의 학급 프로그램. { 일반의 정적인 무효 주된(스트링[] args) { 펑크< >펑크< >인트, 인트>, 펑크< >인트, 인트>> 두번이라. = f => x => f(f(x)); 펑크< >인트, 인트> 플러스 3 = i => i + 3; 변화하다 g = 두번이라.(플러스 3); 콘솔.기입선(g(7)); // 13 } }
또는 마찬가지로 정적 방법을 사용하는 경우:
사용. 시스템.; 일반의 학급 프로그램. { 사적인 정적인 펑크< >인트, 인트> 두번이라.(펑크< >인트, 인트> f) { 돌아가다 x => f(f(x)); } 사적인 정적인 인트 플러스 3(인트 i) => i + 3; 일반의 정적인 무효 주된(스트링[] args) { 변화하다 g = 두번이라.(플러스 3); 콘솔.기입선(g(7)); // 13 } }
클로쥬르
(정의하다두번이라. [f] (fn[x] (f (f x)))) (정의하다플러스 3 [i] (+i 3)) (방어하다g (두번이라. 플러스 3)) (인쇄(g 7)) ; 13
ColdFusion Markup Language(CFML)
두번이라. = 기능.(f) { 돌아가다 기능.(x) { 돌아가다 f(f(x)); }; }; 플러스 3 = 기능.(i) { 돌아가다 i + 3; }; g = 두번이라.(플러스 3); 기입 출력(g(7)); // 13
일반적인 리스프
(삭제하다 두번이라. (f) (람다 (x) (펑콜 f (펑콜 f x)))) (삭제하다 플러스 3 (i) (+ i 3)) (디파이브 g (두번이라. #'플러스 3)) (인쇄물 (펑콜 g 7))
D
수입품 표준.스태디오 : 기입하다; 에일리어스 두번이라. = (f) => (인트 x) => f(f(x)); 에일리어스 플러스 3 = (인트 i) => i + 3; 무효 주된() { 자동 g = 두번이라.(플러스 3); 기입하다(g(7)); // 13 }
다트
인트 기능.(인트) 두번이라.(인트 기능.(인트) f) { 돌아가다 (x) { 돌아가다 f(f(x)); }; } 인트 플러스 3(인트 i) { 돌아가다 i + 3; } 무효 주된() { 최종 g = 두번이라.(플러스 3); 인쇄물(g(7)); // 13 }
엘릭시르
Elixir에서는 모듈 정의와 익명 함수를 혼재시킬 수 있습니다.
디모듈 호프 하다 방어하다 두번이라.(f) 하다 fn(x) -> f.(f.(x)) 끝. 끝. 끝. 플러스_3 = fn(i) -> 3 + i 끝. g = 호프.두번이라.(플러스_3) 입출력.놓다 g.(7) # 13
또는 순수 익명 함수를 사용하여 작곡할 수도 있습니다.
두번이라. = fn(f) -> fn(x) -> f.(f.(x)) 끝. 끝. 플러스_3 = fn(i) -> 3 + i 끝. g = 두번이라..(플러스_3) 입출력.놓다 g.(7) # 13
얼랑
or_filength(또는_filength(오류)([], _) -> 거짓의; or_filength(또는_filength(오류)([F Fs], X) -> or_filength(또는_filength(오류)(Fs, X, F(X)). or_filength(또는_filength(오류)(Fs, X, 거짓의) -> or_filength(또는_filength(오류)(Fs, X); or_filength(또는_filength(오류)(Fs, _, {거짓의, Y}) -> or_filength(또는_filength(오류)(Fs, Y); or_filength(또는_filength(오류)(_, _, R) -> R. or_filength(또는_filength(오류)([재밌어요 에러:is_filename(이것들)/1, 재밌어요 에러:is_atom/1, 재밌어요 에러:is_list/1], 3.23).
이 Erlang 예에서는 고차 함수가or_else/2
는 기능 목록을 가져옵니다(Fs
및 인수(X
) 기능을 평가합니다.F
의론과 함께X
의론으로서함수가F
false를 반환한 후 다음 함수를 반환합니다.Fs
평가됩니다.함수가F
돌아온다{false, Y}
그 다음 기능Fs
의론을 가지고Y
평가됩니다.함수가F
돌아온다R
고차 함수or_else/2
돌아온다R
주의해 주세요.X
,Y
,그리고.R
함수가 될 수 있습니다.이 예에서는,false
.
F#
허락하다 두번이라. f = f >> f 허락하다 플러스_3 = (+) 3 허락하다 g = 두번이라. 플러스_3 g 7 > 인쇄물 %A // 13
가세요
패키지 주된 수입품 "fmt" 기능하다 두번이라.(f 기능하다(인트) 인트) 기능하다(인트) 인트 { 돌아가다 기능하다(x 인트) 인트 { 돌아가다 f(f(x)) } } 기능하다 주된() { 플러스 3 := 기능하다(i 인트) 인트 { 돌아가다 i + 3 } g := 두번이라.(플러스 3) fmt.인쇄(g(7)) // 13 }
함수 리터럴은 식별자( )로 정의할 수 있습니다.twice
또는 익명으로(변수에 따라 다름)plusThree
).
하스켈
두번이라. :: (내부 -> 내부) -> (내부 -> 내부) 두번이라. f = f . f 플러스 3 :: 내부 -> 내부 플러스 3 = (+3) 주된 :: 입출력 () 주된 = 인쇄물 (g 7) -- 13 어디에 g = 두번이라. 플러스 3
J
명시적으로
두번이라.=. 부사. : 'u yu y' 플라스틱=. 동사. : 'y + 3' g=. 플라스틱 두번이라. g 7 13
아니면 암묵적으로
두번이라.=. ^:2 플라스틱=. +&3 g=. 플라스틱 두번이라. g 7 13
Java (1.8 이상)
기능하는 인터페이스만 사용하는 경우:
수입품 java.displaces.function을 참조해 주세요.*; 학급 주된 { 일반의 정적인 무효 주된(스트링[] args) { 기능.< >IntUnary Operator, IntUnary Operator> 두번이라. = f -> f.그리고 나서.(f); IntUnary Operator 플러스 3 = i -> i + 3; 변화하다 g = 두번이라..적용합니다.(플러스 3); 시스템..나가..인쇄(g.applyAsInt(7)); // 13 } }
또는 마찬가지로 정적 방법을 사용하는 경우:
수입품 java.displaces.function을 참조해 주세요.*; 학급 주된 { 사적인 정적인 IntUnary Operator 두번이라.(IntUnary Operator f) { 돌아가다 f.그리고 나서.(f); } 사적인 정적인 인트 플러스 3(인트 i) { 돌아가다 i + 3; } 일반의 정적인 무효 주된(스트링[] args) { 변화하다 g = 두번이라.(주된::플러스 3); 시스템..나가..인쇄(g.applyAsInt(7)); // 13 } }
자바스크립트
화살표 기능 포함:
"엄격하게 사용"; 컨스턴트 두번이라. = f => x => f(f(x)); 컨스턴트 플러스 3 = i => i + 3; 컨스턴트 g = 두번이라.(플러스 3); 콘솔.로그.(g(7)); // 13
또는 기존 구문 사용:
"엄격하게 사용"; 기능. 두번이라.(f) { 돌아가다 기능. (x) { 돌아가다 f(f(x)); }; } 기능. 플러스 3(i) { 돌아가다 i + 3; } 컨스턴트 g = 두번이라.(플러스 3); 콘솔.로그.(g(7)); // 13
줄리아.
줄리아> 기능. 두번이라.(f) 기능. 결과(x) 돌아가다 f(f(x)) 끝. 돌아가다 결과 끝. 2회(1개의 메서드로 기능 확장) 줄리아> 플라스틱(i) = i + 3 plusthree (1가지 방법으로 기능) 줄리아> g = 두번이라.(플라스틱) ( : var " # result # 3 " { type of ( plusthree ) } ( 1 method ) ) 。 줄리아> g(7) 13
코틀린
재밌어요 두번이라.(f: (내부) -> 내부): (내부) -> 내부 { 돌아가다 { f(f(그것)) } } 재밌어요 플러스 3(i: 내부) = i + 3 재밌어요 주된() { 값 g = 두번이라.(::플러스 3) 인쇄(g(7)) // 13 }
루아
기능. 두번이라.(f) 돌아가다 기능. (x) 돌아가다 f(f(x)) 끝. 끝. 기능. 플러스 3(i) 돌아가다 i + 3 끝. 현지의 g = 두번이라.(플러스 3) 인쇄물(g(7)) -- 13
매트랩
함수 결과 = 2회(f) 결과 = @sublic function val = inner(x) val = f(f(x)), 엔드 플러스트리 = @(i) i + 3; g = 2회(plusthree) disp(g(7); % 13
OCaml
허락하다 두번이라. f x = f (f x) 허락하다 플러스_3 = (+) 3 허락하다 () = 허락하다 g = 두번이라. 플러스_3 에 print_int (g 7); (* 13 *) print_newline ()
PHP
<?개요 선언하다(strict_types=1); 기능. 두번이라.(호출 가능한 f달러): 클로즈 { 돌아가다 기능. (인트 x달러) 사용하다 (f달러): 인트 { 돌아가다 f달러(f달러(x달러)); }; } 기능. 플러스 3(인트 i달러): 인트 { 돌아가다 i달러 + 3; } $g = 두번이라.('+3'); 메아리치다 $g(7), "\n"; // 13
또는 모든 함수가 변수에 있는 경우:
<?개요 선언하다(strict_types=1); $140 = fn(호출 가능한 f달러): 클로즈 => fn(인트 x달러): 인트 => f달러(f달러(x달러)); $+3 = fn(인트 i달러): 인트 => i달러 + 3; $g = $140($+3); 메아리치다 $g(7), "\n"; // 13
화살표 함수는 부모 [1]스코프에서 오는 변수를 암묵적으로 캡처하는 반면 어나니머스 함수는 다음을 필요로 합니다.use
키워드를 지정합니다.
펄
사용하다 엄격한.; 사용하다 경고.; 후보선수 두번이라. { 나의 (f달러) = @_; 후보선수 { f달러->(f달러->(@_)); }; } 후보선수 플러스 3 { 나의 (i달러) = @_; i달러 + 3; } 나의 $g = 두번이라.(\&플러스 3); 인쇄물 $g->(7), "\n"; # 13
또는 모든 함수가 변수에 있는 경우:
사용하다 엄격한.; 사용하다 경고.; 나의 $140 = 후보선수 { 나의 (f달러) = @_; 후보선수 { f달러->(f달러->(@_)); }; }; 나의 $+3 = 후보선수 { 나의 (x달러) = @_; x달러 + 3; }; 나의 $g = $140->($+3); 인쇄물 $g->(7), "\n"; # 13
파이썬
>>>방어하다 두번이라.(f): ... 방어하다 결과(x): ... 돌아가다 f(f(x)) ... 돌아가다 결과 >>>플러스_3 = 람다 i: i + 3 >>>g = 두번이라.(플러스_3) >>>g(7) 13
Python 데코레이터 구문은 함수를 고차 함수를 통해 전달한 결과로 대체하기 위해 자주 사용됩니다.예: 기능g
동등하게 실장할 수 있습니다.
>>>@parames(@parames) ...방어하다 g(i): ... 돌아가다 i + 3 >>>g(7) 13
R
두번이라. <-> 기능.(f) { 돌아가다(기능.(x) { f(f(x)) }) } 플러스 3 <-> 기능.(i) { 돌아가다(i + 3) } g <-> 두번이라.(플러스 3) > 인쇄물(g(7)) [1] 13
라쿠
sub twice(콜 가능:D $f) {return sub { $f($f($^x)}; } 서브플러스3(Int:D $i) {return $i + 3; } my $g = 2회(&plusThree); $g(7); # 13이라고 말하세요.
Raku에서는 모든 코드 객체가 폐쇄이므로 어휘 변수가 함수 내부에서 "닫힘"되기 때문에 외부 스코프에서 내부 "렉시컬" 변수를 참조할 수 있습니다.또한 Raku는 변수에 할당하거나 익명으로 호출할 수 있는 람다 식에 대해 "pointy block" 구문을 지원합니다.
루비
방어하다 두번이라.(f) ->(x) { f.불러(f.불러(x)) } 끝. 플러스_3 = ->(i) { i + 3 } g = 두번이라.(플러스_3) 놓다 g.불러(7) # 13
녹
fn 2회(f: include Fn(i32) -> i32) -> include Fn(i32) -> i32 { move x f(f(x)} } fn plus_3(i: i32) -> i32 { + 3} fn main() {let g = 2회(+3); ln!{7}, g}, 13,
스칼라
물건 주된 { 방어하다 두번이라.(f: 내부 => 내부): 내부 => 내부 = f 작곡하다 f 방어하다 플러스 3(i: 내부): 내부 = i + 3 방어하다 주된(args: 어레이[스트링]): 구성 단위 = { 값 g = 두번이라.(플러스 3) 인쇄물(g(7)) // 13 } }
스킴
(정의하다(더하다 x y) (+x y)) (정의하다(f x) (람다(y) (+x y))) (표시((f 3) 7)) (표시(더하다 3 7))
이 구성표 예제에서는 고차 함수가(f x)
카레를 구현하기 위해 사용합니다.단일 인수를 사용하여 함수를 반환합니다.표현식의 평가((f 3) 7)
먼저 평가 후 함수를 반환합니다.(f 3)
반환된 함수는(lambda (y) (+ 3 y))
그런 다음 반환된 함수를 인수로 7로 평가하고 10을 반환합니다.이것은 다음 식에 해당합니다.(add 3 7)
,부터(f x)
카레 형태와 동등하다(add x y)
.
재빠르다
기능하다 두번이라.(_ f: @탈옥 (내부) -> 내부) -> (내부) -> 내부 { 돌아가다 { f(f($0)) } } 허락하다 플러스 3 = { $0 + 3 } 허락하다 g = 두번이라.(플러스 3) 인쇄물(g(7)) // 13
TCL
두 번 {{f x}{set $f [set $f $x]} set plus3 {{i} {return [expr $i + 3]}} # 결과 : 13 puts [2배 $+ 적용]3 7 ]
TCL은 apply 명령을 사용하여 익명 함수를 적용합니다(8.6 이후).
XACML
XACML 표준은 Atribut bag의 여러 값에 함수를 적용하기 위해 표준에서 고차 함수를 정의합니다.
규칙. allow Entry(허용 엔트리){ 허용하다 조건. AnyOfAny(함수)[문자열 동일], 시민권, 허가된 시민권) }
XACML의 고차 함수 목록은 여기에서 확인할 수 있습니다.
XQuery
선언하다 기능. 로컬: 개요($f, $x) { $f($f($x)) }; 선언하다 기능. 로컬: 플러스트리($i) { $i + 3 }; 로컬: 개요(로컬: 플러스트리#1, 7) (: 13 :)
대체 수단
함수 포인터
C, C++ 및 Pascal과 같은 언어의 함수 포인터를 사용하면 프로그래머가 함수에 대한 참조를 전달할 수 있습니다.다음 C 코드는 임의 함수의 적분에 대한 근사치를 계산합니다.
#실패하다 <stdio.h> 이중으로 하다 광장(이중으로 하다 x) { 돌아가다 x * x; } 이중으로 하다 입방체(이중으로 하다 x) { 돌아가다 x * x * x; } /* 간격 [a,b] */ 내의 f()의 적분을 계산합니다. 이중으로 하다 일체형(이중으로 하다 f(이중으로 하다 x), 이중으로 하다 a, 이중으로 하다 b, 인트 n) { 인트 i; 이중으로 하다 합 = 0; 이중으로 하다 dt = (b - a) / n; 위해서 (i = 0; i < > n; ++i) { 합 += f(a + (i + 0.5) * dt); } 돌아가다 합 * dt; } 인트 주된() { 인쇄물(%g\n", 일체형(광장, 0, 1, 100)); 인쇄물(%g\n", 일체형(입방체, 0, 1, 100)); 돌아가다 0; }
C 표준 라이브러리의 qsort 함수는 함수 포인터를 사용하여 고차 함수의 동작을 에뮬레이트합니다.
매크로
매크로를 사용하여 고차 함수의 효과를 얻을 수도 있습니다.단, 매크로에서는 변수 캡처의 문제를 쉽게 회피할 수 없습니다.또한 대량의 코드가 중복되어 컴파일러의 최적화가 어려워질 수 있습니다.매크로는 일반적으로 강하게 입력되지 않지만 강하게 입력된 코드가 생성될 수 있습니다.
동적 코드 평가
다른 명령형 프로그래밍 언어에서는 평가 범위에서 동적으로 코드(Eval 또는 Execute 연산이라고도 함)를 실행함으로써 고차 함수를 통해 얻은 것과 동일한 알고리즘 결과를 얻을 수 있습니다.이 방법에는 다음과 같은 중대한 결점이 있을 수 있습니다.
- 실행할 인수 코드는 일반적으로 정적으로 입력되지 않습니다.이러한 언어들은 일반적으로 실행할 코드의 적절한 형식과 안전성을 판단하기 위해 동적 입력에 의존합니다.
- 인수는 보통 문자열로 제공되며 값은 런타임까지 알 수 없습니다.이 문자열은 프로그램 실행 중에 컴파일(저스트 인 타임 컴파일을 사용하여)하거나 해석에 의해 평가되어야 하며 런타임에 추가 오버헤드가 발생하며 일반적으로 효율성이 떨어지는 코드를 생성해야 합니다.
물건들
고차 함수를 지원하지 않는 객체 지향 프로그래밍 언어에서는 객체가 효과적인 대체물이 될 수 있습니다.객체의 메서드는 본질적으로 함수처럼 작용하며 메서드는 객체를 파라미터로 받아들여 반환값으로 객체를 생성할 수 있습니다.그러나 객체는 종종 순수한 함수에 비해 추가 런타임 오버헤드를 전달하고 객체와 메서드를 정의하고 인스턴스화하기 위한 보일러 플레이트 코드를 추가합니다.스택 베이스(히프 베이스가 아닌) 오브젝트 또는 구조를 허용하는 언어를 사용하면 이 방법을 보다 유연하게 사용할 수 있습니다.
함수를 반환하는 함수와 함께 Free Pascal에서 단순 스택 기반 레코드를 사용하는 예:
프로그램. 예; 유형 인트 = 정수; 탁시 = 기록. x, y: 인트; 끝.; Tf = 기능. (xy: 탁시): 인트; 기능. f(xy: 탁시): 인트; 시작한다. 결과 := xy.y + xy.x; 끝.; 기능. g(기능하다: Tf): Tf; 시작한다. 결과 := 기능하다; 끝.; 변화하다 a: Tf; xy: 탁시 = (x: 3; y: 7); 시작한다. a := g(@f); // 함수를 "a"로 되돌립니다. 기입하다(a(xy)); // 10 인쇄 끝..
함수a()
를 취득하다Txy
입력으로 기록하고 레코드 합계의 정수 값을 반환합니다.x
그리고.y
필드 (3 + 7)
기능 해제
기능 해제를 사용하면 퍼스트 클래스 함수가 없는 언어로 고차 함수를 구현할 수 있습니다.
// 기능 해제된 기능 데이터 구조 템플릿< >타이프네임 T> 구조 더하다 { T 가치; }; 템플릿< >타이프네임 T> 구조 DivBy { T 가치; }; 템플릿< >타이프네임 F, 타이프네임 G> 구조 구성. { F f; G g; }; // 기능 해제된 기능 애플리케이션 구현 템플릿< >타이프네임 F, 타이프네임 G, 타이프네임 X> 자동 적용합니다.(구성.< >F, G> f, X arg) { 돌아가다 적용합니다.(f.f, 적용합니다.(f.g, arg)); } 템플릿< >타이프네임 T, 타이프네임 X> 자동 적용합니다.(더하다< >T> f, X arg) { 돌아가다 arg + f.가치; } 템플릿< >타이프네임 T, 타이프네임 X> 자동 적용합니다.(DivBy< >T> f, X arg) { 돌아가다 arg / f.가치; } // 고차 합성 함수 템플릿< >타이프네임 F, 타이프네임 G> 구성.< >F, G> 작곡하다(F f, G g) { 돌아가다 구성.< >F, G> {f, g}; } 인트 주된(인트 argc, 컨스턴트 차* argv[]) { 자동 f = 작곡하다(DivBy< >흘러가다>{ 2.0f }, 더하다< >인트>{ 5 }); 적용합니다.(f, 3); // 4.0f 적용합니다.(f, 9); // 7.0f 돌아가다 0; }
이 경우 함수 오버로드를 통해 다른 기능을 트리거하는 데 다른 유형이 사용됩니다.이 예에서는 오버로드된 함수에 시그니처가 있습니다.auto apply
.
「 」를 참조해 주세요.
- 퍼스트 클래스 기능
- 조합논리
- 기능 수준 프로그래밍
- 기능 프로그래밍
- 카파 미적분 - 고차 함수를 제외한 함수에 대한 형식주의
- 전략 패턴
- 상위 메시지
레퍼런스
- ^ "PHP: Arrow Functions - Manual". www.php.net. Retrieved 2021-03-01.