모든 함수는 비 공통 부분과 공통 부분이 존재합니다. 비 공통 부분은 인자로 주어져 호출에 따라 달라집니다.

만약 함수 값을 메소드의 인자로 전달하면 함수 값 내부 알고리즘이 전달되는 것이기에 메소드 내부 알고리즘을 동적으로 변경할 수 있습니다.

그래서 특정 메소드의 일정 부분이 동일하고 나머지 로직이 다르다면 기존에는 다른 로직마다 별도 메소드를 정의해야 하지만 함수 값을 인자로 전달받을 수 있다면 다른 로직만 함수값에 따라 변경하면 되기 때문에

하나의 메소드만 정의하면 됩니다. 따라서 코드 중복을 줄일 수 있습니다.

여기서 함수 값을 인자로 받는 함수를 고차 함수라고 부릅니다.

 

왼쪽의 FileMatcher 싱글톤 객체를 보면 메소드 파라미터, for, yield 까지 3개의 메소드에서 중복을 보입니다.

종복이 생기게 되면 만약 다른 fileMatcher 메소드를 추가한다면 예를 들어 filesEnding이 아닌 filesStarting을 추가한다면 중복해서 메소드를 추가해야 합니다.

그리고 여기서는 폴더의 모든 파일에 대해 query를 매치하고 있는 데 만약 첫 번째 파일만 제외한다고 하면 3개의 메소드 모두 수정을 해야 합니다.

그래서 왼쪽 코드에서 공통적인 부분과 비 공통 부분을 나눠 비 공통 부분을 인자로 전달하게 됩니다. 여기서 비 공통 부분은 if문 내부 조건이 됩니다.

이 조건은 값이 아닌 로직으로 되어 있기 때문에 인자에 함수 값을 전달해서 비 공통 부분을 변경할 수 있습니다.

오른쪽과 같이 filesMatching이라는 고차 함수를 정의합니다. 공통 부분이 들어간 것을 볼 수 있고 두 번째 인자로 메소드를 받습니다.

if 절에서 인자로 받은 matcher을 호출해 비 공통 부분이 인자값에 따라 달라지도록 합니다.

 

 

왼쪽 코드는 filesEnding에서 query 인자를 받고 이 인자를 또 filesMatching에 전달하는 데 굳이 그럴 필요는 없습니다.

클로저를 사용하면 메소드에서 외부 스코프의 변수에 접근 가능하기 때문에 오른쪽과 같이 endsWith의 인자에 query를 바로 넣을 수 있습니다.

 

API에 고차 함수를 포함 시킨 좋은 예는 스칼라 컬렉션 타입의 특별 루프 메소드입니다.

대표적으로 컬렉션의 exists 메소드가 있습니다.

클라이언트에서 인자로 받은 nums에서 음수가 있는 지 확인하기 위해 containNeg 메소드를 정의하고 홀수가 있는 지 확인하기 위해 containsOdd를 정의했습니다.

메소드를 보면 빨간 색 로직 부분을 제외하고 공통 부분인 걸 볼 수 있는 데 스칼라의 컬렉션 타입에서는 왼쪽 코드의 공통 부분과 비공통 부분인 if 조건 함수 값을 인자로 받는 exists 고차함수가 정의되어 있습니다.

그래서 왼쪽 코드를 exists 메소드를 활용해 오른쪽과 같이 단순하게 만들 수 있습니다.

 

커링은 인자 목록이 2개 이상인 함수를 의미합니다.

기존 함수는 왼쪽과 같이 전체 인자가 하나의 괄호 안에 들어가는 데 커링은 오른쪽 함수와 같이 인자를 여러 목록으로 나눌 수 있습니다.

인자를 여러 목록으로 나눴기 때문에 메소드를 호출할 때도 괄호로 나눠서 하게 됩니다.

실제로 curriedSum이 호출되는 과정을 보면 함수를 2번 호출하게 됩니다. 먼저 x가 입력된 함수 값이 반환됩니다. 왼쪽 아래 코드의 first와 같습니다.

그리고 그 함수값에 y를 적용하게 됩니다.

커링은 위치 표시자를 활용해서 부분 적용 함수로 사용할 수 있습니다.

curriedSum(1)_을 하게 되면 1을 제외한 나머지를 받는 부분 적용 함수로 바뀌게 되 부분 적용함수를 사용할 때 요구하는 인자값만 전달하면 됩니다.

 

컴퓨터 과학에서 추상화(abstraction)는 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것을 말합니다.

첫 번째 코드의 경우 두 번 연산을 수행하는 흐름 제어를 추상화한 것인데 위와 같이 하면 여러가지 다른 로직을 가진 메소드들을 twice에 인자로 전달하는 것만으로 두 번 연산을 수행할 수 있도록 할 수 있습니다.

아래 코드는 함수에서 대신 자원을 열고 닫아주는 흐름 제어를 추상화한 것인데 빌려주기 패턴이라고도 합니다.

 

Call by value , 영어 그대로 값을 참조합니다. 즉 함수가 인자로 전달 될 경우, 그 즉시 함수를 평가하는 걸 말합니다

callByName이란? 값이 파라미터로 전달 될 때 평가되지 않고, 실제로 call이 될 때 평가하는 것을 말합니다.

위 예에서 Call by Value를 할 경우 assertionEnabledfalse일 때도 myAssert 괄호 안의 표현을 평가한다. 필요하지 않은 계산을 하는 부수 효과가 생기게 됩니다.

그러나 Call by Name의 경우 assertionEnabledfalse일 때 표현식을 계산하지 않기 때문에 부수 효과가 발생하지 않습니다.

Call by Name 코드를 보면 myAssert 인자로 “()=>5>3” 표현식을 줬는 데 읽기 힘듭니다. 그래서 아래와 같이 “()”를 함수 인자에서 생략하면 가독성 있게 파라미터를 전달할 수 있습니다.

+ Recent posts