0

함수를 매개 변수를 통해 전달할 수있는 언어의 장점이 무엇인지 궁금합니다. 그리고 이것과 함께 할 수있는 몇 가지 예가 있습니다.매개 변수를 통해 서브 루틴/함수 전달하기

어떤 인기있는 프로그래밍 언어에서이 기능을 사용할 수 있습니까?

+1

두 번째 질문은 가장 좋은 [위키 백과] 응답한다 (http://en.wikipedia.org/wiki/First-class_function) 또는 [로제타 코드 (http://rosettacode.org/wiki/First-class_functions) . 또한 관심이 있습니까? 함수 포인터 (매개 변수로 전달할 수 있지만 대부분의 언어는 더 많은 것을 허용합니다), 또는 함수의 장점을 일반적으로 일류 값으로 사용합니까? – delnan

답변

3

개체 모음이 있다고 가정하고 몇 가지 기준에 따라 정렬하려고합니다. 내가 함수에 함수를 전달할 수있는 경우

, 그것은 쉽게 :

collection.sort((a, b) => a.SomeProperty.compareTo(b.SomeProperty)); 

나는,이 같은 일을하기 위해 나는 기본적으로 정렬 알고리즘을 내가 원하는 때마다 다시 구현할 필요가없는 경우 다른 기준에 따라 분류 할 수 있습니다.

+0

C의 함수 포인터조차도 이것을 할 수 있습니다 (generic이나 type-safe는 아니지만). 이 예제에서와 같이 익명 함수는 관련이 있지만 다른 것입니다. – delnan

+0

예제에는 익명의 함수가 꼭 필요한 것은 아닙니다. 이름이 지정된 함수를 전달할 수있는 기능을 사용하여 동일한 위치를 다소 달성 할 수 있습니다. 큰 요점은 Java와 같은 언어에서 함수를 인수로 전달하지 못하게하는 것입니다. 클래스를 간단하게 인수로 전달할 수 있기 때문에 꽤 못생긴 해킹을해야합니다. 동일한 기능. –

1

장점은 일반 값으로 쉽게 표현되지 않는 것들보다 기능을 매개 변수화 할 수 있다는 것입니다.

예를 들어, 콜렉션에서 특정 술어를 충족시키는 항목을 찾으려하거나 콜렉션의 모든 항목이 술어를 충족시키는 지 여부를 찾으려는 경우, 술어는 요소에서 함수로 가장 자연스럽게 표현됩니다 bool을 입력하십시오.

다른 일반적인 예로는 비교 함수를 인수로 사용하는 정렬 함수가 있으므로 컬렉션의 요소를 사용자 지정 정렬 키로 정렬 할 수 있습니다.

물론 함수를 인수로 허용하지 않지만 객체 시스템 (java : 읽기)을 사용하는 언어에서는 정렬 기능에 대한 특정 인터페이스를 구현하는 객체를 사용하여이 문제를 해결할 수 있습니다.

어떤 인기있는 프로그래밍 언어가 [인수를 함수로 전달할 수 있습니까?]

C, C++, C#, Objective C, Python, Ruby, Perl, PHP, Javascript 및 기본적으로 모든 기능적 또는 기능적 언어.

목록의 다른 언어와 달리 C 및 C++ (C++ 0x 이전)은 클로저를 가지고 있지 않습니다.

+0

C++ 0x는 익명의 함수와 클로저를 추가합니다. 그러나이 질문은 폐쇄에 관한 것이 아닙니다. – delnan

1

다른 기능에 기능을 전달할 수 있다는 이점은 더 깔끔하고 일반적인 코드를 작성할 수 있다는 것입니다. 예를 들어, 목록에있는 모든 숫자를 요약 상당히 현실적인 기능을 고려

sum []  = 0 
sum (x:xs) = x + sum xs 

이 당신에게 생소 할 수 하스켈 구문에; 두 줄은 입력이 빈 목록인지 여부에 따라 두 가지 다른 경우를 정의합니다.이 경우 합이 0 인 경우 또는 x이 목록 xs 앞에 붙는 경우이 경우 합계는 xxs의 합을 더한 값입니다.보다 전통적인 언어 (안 특히 하나)에서, 지금

function sum(xs) { 
    var total = 0 
    for x in xs { 
    total = x + total 
    } 
    return total 
} 

이있을 것이다, 대신, 우리는 목록에있는 번호의 제품을 찾을한다고 가정 :

product []  = 1 
product (x:xs) = x * product xs 

에서 전통적인 언어라면 더 좋아 보일 것입니다.

function product(xs) { 
    var total = 1 
    for x in xs { 
    total = x * total 
    } 
    return total 
} 

흥미롭게도이 두 함수는 거의 비슷하게 보입니다. 유일한 차이점은 01으로 바뀌고 +*으로 바뀌 었습니다. 그리고 실제로, 우리가 sum+ 모두를 일반화 할 수 있음을 밝혀 : 두 인수 기능 f, 일정한 i 및 목록 : 여기

foldr f i []  = i 
foldr f i (x:xs) = f x (foldr f i xs) 

foldr는 세 개의 인수를 취합니다. 목록이 비어 있으면 상수 (예 :, sum [] = 0)를 반환합니다. 그렇지 않으면 함수를 (a) 목록의 첫 번째 요소와 (b) 나머지 목록을 접은 결과에 적용합니다. 보다 전통적인 언어에서 this'd 이것은 우리가 sumproduct 단순히

sum  = foldr (+) 0 
product = foldr (*) 1 
여기

((+)(*) 추가 2 개의 인수를 기능입니다을 단순화 할 수 있다는 것을 의미

function foldr(f,i,xs) 
    var result = i 
    for x in xs { 
    result = f(x, result) 
    } 
    return result 
} 

같은 모양 인수를 각각 곱하십시오.) 일급 함수 없이는 이것을 할 수 없습니다. (내가하고있는 다른 일은 마지막 인자를 버리는 것이다. 이것은 currying이라고 불리며, 다소 편리하다. 그 아이디어는 그 모든 인수를 foldr에게주지 않으면 나머지 부분을 기대하는 함수를 반환한다는 것이다. 그러나 혼동 스럽다면 정의가 sum xs = foldr (+) 0 xs이라고 가정 해보십시오.)

하지만 여기에 흥미로운 부분이 있습니다. 가정 당신은 숫자의 목록을 가지고, 당신은 목록에있는 모든 수의 제곱 계산하려면 :

squares []  = [] 
squares (x:xs) = (x^2) : squares xs 

function squares(xs) { 
    var result = [] 
    for x in xs { 
    result = result ++ [x^2] 
    } 
    return result 
} 

을하지만 이것은 분명히 abstractable입니다 : 당신의 모든 요소를 ​​부정하고자한다면 거의 정확히 같은 코드가 작동 것이다 귀하의 목록, 또는 이메일 목록이 있고 발신자를 얻고 싶다면 무엇이든간에. 그래서 우리는 추상적 인 :

map f []  = [] 
map f (x:xs) = f x : map f xs 

function map(f,xs) { 
    var result = [] 
    for x in xs { 
    result = result ++ [f(x)] 
    } 
    return result 
} 

squares  = map (^2) # (^2) is the function which squares its argument. 
negations = map negate 
emailSenders = map getSender 

그러나 흥미롭게도, 우리는 또한 우리의 이전 foldr의 관점에서 map을 구현할 수 있습니다. 첫째, 우리는 함수의 합성, .을 정의해야

f . g = \x -> f (g x) 

이는 fg의 구성 자체가 g 결과에 x에와 f 적용 하나 개의 인수, 새로운 익명 함수 말합니다. 그리고 지금, 우리는 map를 정의 할 수 있습니다 :

다음
map f = foldr ((:) . f) [] 

, (:) 목록에 앞에 추가하는 요소 요소 및 목록을 받아, 반환하는 함수입니다.(:) . f\x -> (:) (f x)과 같으며 (앞서 언급 한 currying 규칙에 따라) \x xs -> f x : xs과 같습니다. 즉, 접기의 각 단계마다 우리가 지금까지 가지고있는 것의 앞에 f x을 붙입니다. (이것은하지 않습니다 말하자면, 우리에게 mapfoldr 때문에 작품 "내부 아웃"의 반대를 제공합니다.)

map의이 정의는 foldr에 전달하는 기능을 구성 할 고차 기능 .를 사용합니다. 많은 함수가 매개 변수로 전달됩니다! 그리고 이것은 우리가 쓰기

f &&& g = \x -> (f x, g x) 

같은 일을 그리고

sendersAndRecipients = map (getSender &&& getRecipient) . fetchEmails 

당신은 값으로 기능을 처리 할 수있는 전력을 많이 얻을 작성하는 것을 사용할 수 있습니다. map 또는 &&&과 같은 일반 절차를 작성하여 나중에 간결하면서도 읽을 수있는 코드를 작성할 수 있습니다. 함수 전달은 sendMessage(theMessage,fn) (fn은 응답을받을 때 실행되는 함수 임) 콜백에도 편리합니다. 일하는 것은 아주 자연스러운 방법 일뿐입니다.

지원 언어 : 솔직히 말해서 Wikipedia는 내가 아는 것보다 더 잘 알고 있습니다. 그러나 나는 그것을 줄 것이다. C와 C++은 일종의 : 함수를 인라인으로 작성할 수는 없지만 함수 포인터를 전달할 수는 있습니다. 어느 언어에서도 대단히 일반적이지는 않습니다 (심지어 C 언어도 적습니다). 어떤 OO 언어라도, 당신이 원하는 함수 인 하나의 메소드를 가진 클래스를 정의 할 수 있지만, 이것은 대단히 clunky하다. 그럼에도 불구하고 이것이 자바가하는 일이다. 반면 C#에는 실제로 매개 변수로 전달할 수있는 함수가 있습니다. 루비 (특정 유스 케이스의 특수 구문 인 "블록"도 있음), 파이썬, 펄 및 자바 스크립트는 함수 프로그래밍 언어와 마찬가지로 전달 함수를 지원합니다 : Lisps (Scheme, Common Lisp, Clojure, ...); ML 가족 (SML, OCaml, ...); 하스켈 (ML 가족과 함께 할 수있는); 스칼라; 다른 사람. 유용한 기능이기 때문에 널리 보급되는 것은 놀라운 일이 아닙니다.

관련 문제