일급 객체(First-class object)와 고차 함수(Higher-order function)

김대협·2023년 1월 8일
0

일급 객체(First-class object)와 고차 함수(Higher-order function)


일급 객체(First-class object)란 다른 객체들에게 적용 가능한 연산을 모두 지원하는 객체를 뜻한다.

자바에서 Integer, String 과 같은 객체들은 모두 일급 객체이다.

자바 프로그래밍 언어의 다양한 구조체(메서드, 클래스 같은)는 프로그램을 실행하는 동안 이러한
모든 구조체를 자유롭게 전달할 수는 없다. 이렇게 전달할 수 없는 구조체는 이급 시민(Second-class citizen)이다.

일급 객체라는 용어는 Christopher Strachey 에 의해 1960년대 미국 시민 권리에서 유래되어
일급 시민을 뜻하는 First-class citizen 에서 기원되어 사용되어 왔다.

일급 값, 일급 시민, 일급 객체 등 용어에 혼선을 느끼지 말고 동일함을 인식하면 된다.

In programming language design, a first-class citizen (also type, object, entity, or value)
- en.wikipedia

일급 객체의 성립 조건


  • 변수나 데이터에 할당할 수 있어야 한다.
  • 함수의 인자로 전달할 수 있어야 한다.
  • 함수의 반환 값으로 반환될 수 있어야 한다.
public class FirstClassCitizenTest {

    private static <T> T retValue( T data ) {
        return data;
    }

    private static <T> void displayValue( T data, Consumer<T> consumer ) {
        consumer.accept( data );
    }

    private static <T> Consumer<T> getConsumer() {
        return ( data ) -> System.out.println( data );
    }

    public static void doTest() {
        // 변수나 데이터에 할당할 수 있어야 한다.
        Consumer<Integer> retIntFunc = FirstClassCitizenTest::retValue;
        retIntFunc.andThen( System.out::println ).accept( 1234 );

        // 함수의 인자로 전달할 수 있어야 한다.
        displayValue( "ntigo", System.out::println );

        // 함수의 리턴 값으로 반환할 수 있어야 한다.
        displayValue( "test", getConsumer() );
    }
}

함수형 인터페이스로 인한 메서드의 일급 값 취급


스칼라, 클로저와 같은 함수형 언어에서 메서드를 일급 값으로 사용하면 프로그래머가 활용할 수 있는
도구가 다양해지면서 프로그래밍이 수월해짐을 경험했다.
이러한 기능에 익숙해지면 일급 객체가 부족한 프로그래밍 언어의 사용을 기피할 만큼 매력적이다.

자바의 메서드는 JDK 8 이전(함수형 인터페이스의 도입 이전) 위의 조건에 해당되지 않았다.
JDK 8 의 설계자들은 Functional Programming 의 패러다임을 더는 늦출 수 없었는지 모른다.

고차 함수 (Higher-order function)


함수를 일급 객체로 취급할 수 있다는 것은 고차 함수로 인해 아주 큰 차이를 만든다.
함수형 프로그래밍 언어에서 함수는 일차 구성원이다. 고차원 함수는 하나 이상의 함수를 인수로 받거나, 또는 함수를 결과로 반환을 수행하는 함수이다.

// 고차 함수
List<Person> people = new ArrayList<>();
people.add( new Person( "ntigo", 30, 183 ) );
people.add( new Person( "atigo", 20, 160 ) );
people.add( new Person( "btigo", 40, 170 ) );
people.add( new Person( "ctigo", 35, 175 ) );

Predicate<Person> ageLessThan35 = person -> person.getAge() < 35;
Predicate<Person> heightLessThan170 = person -> person.getHeight() > 170;

// filter 메서드는 Predicate 를 매개변수로 취하는 고차 함수이다.
// filter 메서드는 각 요소에 적용되어 스트림에 포함되어야 하는지 확인하고 filter 메서드 내에서
// test() 메서드가 호출되고 람다 표현식이 실행된다.
people.stream().filter( ageLessThan35 ).filter( heightLessThan170 )
        .forEach( System.out::println );

Reference


Java 8 in Action (2014) - Raoul-Gabriel Urma, Mario Fusco, and Alan Mycroft
First-class citizen(en.wikipedia) - https://en.wikipedia.org/wiki/First-class_citizen


© 2023.1 Written by Boseong Kim.
profile
기록하는 개발자

0개의 댓글