Kotlin

고차 함수(higher-order functions)

Hcode 2023. 2. 17.

 


 

고차 함수란?

 

고차 함수는
  다른 함수를 인자로 가져오거나 함수를 결과로 반환하는 함수입니다.

이는 모듈화 되고 재사용 가능하며 유연한 코드를 도와주는 Kotlin의 강력한 기능입니다.

 

고차 함수를 사용하여 광범위한 데이터 유형 및 작업에 적용할 수 있는

  매핑, 필터링 및 컬렉션 폴딩과 같은 추상화를 만들 수 있습니다.

또한 특정 작업이나 문제 영역에 대해

  보다 자연스러운 구문을 제공하는 영역별 언어를 만드는 데 사용할 수도 있습니다.

 


 

고차 함수를 사용하는 이유

재사용성

다른 함수를 매개변수로 사용하면

  고차 함수를 코드베이스의 다른 부분에서 더 쉽게 재사용할 수 있습니다.

이렇게 하면 작성하고 유지 관리해야 하는 코드의 양이 줄어들어

  시간과 노력을 절약할 수 있습니다.

 

모듈성

고차 함수를 사용해서 복잡한 작업을 더 작고 관리하기 쉬운 조각으로 분해하여

  더 모듈화되고 구성 가능한 코드를 만들 수 있습니다.

이렇게 하면 코드에 대해 더 쉽게 추론하고 오류나 버그의 위험을 줄일 수 있습니다.

 

유연성

고차 함수를 사용하여

  다양한 사용 사례에 맞게 사용자 정의할 수 있는,

    보다 유연하고 적응 가능한 코드를 생성할 수 있습니다.

다른 함수를 매개 변수로 전달하면

  소스 코드를 수정하지 않고도 필요에 맞게 고차 함수의 동작을 변경할 수 있습니다.

 

표현성

고차 함수는 보다 선언적인 방식으로 작업을 정의할 수 있도록 하여

  코드를 보다 표현적이고 읽기 쉽게 만들 수 있습니다.

예를 들어 filter() 함수를 사용하여

  조건에 따라 컬렉션에서 요소를 선택하기 위한

    보다 표현적인 구문을 만들 수 있습니다.

 

도메인별 언어

고차 함수를 사용하여

  특정 작업 또는 문제 도메인에 대해 보다 자연스러운 구문을 제공하는

    DSL(Domain-specific languages; 도메인별 언어)을 만들 수 있습니다.

DSL을 사용하면

  해결하려는 문제와 더 밀접하게 일치하는 코드를 더 쉽게 작성할 수 있고

    다른 개발자가 코드를 더 쉽게 이해하며 사용할 수 있습니다.

 

 


 

예제

예제 목록


 

예제1

fun mapToString(numbers: List<Int>, toString: (Int) -> String): List<String> {
    val result = mutableListOf<String>()
    for (number in numbers) {
        result.add(toString(number))
    }
    return result
}

정수 리스트와 함수(정수를 가져와 문자열을 반환)라는 두 개의 매개 변수를 사용하는

  mapToString()이라는 함수를 정의합니다.

이 함수는 정수 리스트를 반복하며

  제공된 함수를 호출해서

    각 정수를 문자열로 변환하고 잇습니다.

그런 다음 결과 문자열을 반환합니다.

 

mapToString() 함수를 사용하려면

  정수를 문자열로 변환하는 방법을 정의하는 람다 식을 정의하고

    이를 함수의 매개 변수로 전달하면 됩니다.

val numbers = listOf(1, 2, 3, 4, 5)

val strings = mapToString(numbers) { number -> "Number $number" }

println(strings) // Output: ["Number 1", "Number 2", "Number 3", "Number 4", "Number 5"]

numbers라는 정수 리스트를 정의하고

  numbers와 각 정수에 문자열 "Number "를 추가하는 람다 식을 인자로 사용하여

    mapToString() 함수를 호출합니다.

 


 

filter()

val words = listOf("apple", "banana", "orange", "pear", "grape")

val shortWords = words.filter { word -> word.length <= 5 }

println(shortWords) // Output: ["apple", "pear", "grape"]

filter() 함수를 사용하여

  길이가 5자 이하인 단어만 포함하는

    shortWords라는 리스트를 만들게 됩니다.

words 리스트의 각 단어 길이를 확인하고

  길이가 5자 이하이면

    true를 반환하는 람다 식을 filter() 함수에 전달합니다.

 


 

map()

val numbers = listOf(1, 2, 3, 4, 5)
val strings = numbers.map { "Number $it" }
println(strings) // Output: ["Number 1", "Number 2", "Number 3", "Number 4", "Number 5"]

원래 리스트의 각 정수에

  문자열 "Number "를 추가하는 람다 식을 적용하여 새 문자열 목록을 만들기 위해

    map() 함수를 사용합니다.

 

it 키워드는 목록에서 처리 중인 현재 항목을 나타냅니다.

 


 

fold()

val numbers = listOf(1, 2, 3, 4, 5)
val sum = numbers.fold(0) { acc, number -> acc + number }
println(sum) // Output: 15

fold() 함수를 사용하여

  누산기에 각 숫자를 추가하여 정수 목록을 단일 값으로 줄입니다.

fold() 함수는

  누산기에 대한 현재 누산기 값(초기 값부터 시작)과 처리 중인 현재 항목을 가져와

    새 누산기 값을 반환하는 람다 식을 사용합니다.

누산기(Accumulator)는 데이터 레지스터로 처리 결과를 임시로 보유하는 역할

 


 

고차 함수를 사용하여 HTML 문서를 작성하기 위한 DSL 정의

fun html(block: Tag.() -> Unit): String {
    val tag = Tag("html")
    tag.block()
    return tag.toString()
}

class Tag(private val name: String) {
    private val children = mutableListOf<Tag>()
    private val attributes = mutableMapOf<String, String>()

    fun <T : Tag> T.set(name: String, value: String?): T {
        value?.let { attributes[name] = value }
        return this
    }

    fun <T : Tag> T.add(child: Tag): T {
        children.add(child)
        return this
    }

    override fun toString() =
        "<$name${renderAttributes()}>" +
                "${renderChildren()}" +
                "</$name>"

    private fun renderAttributes(): String {
        val builder = StringBuilder()
        attributes.forEach { (name, value) ->
            builder.append(" $name=\"$value\"")
        }
        return builder.toString()
    }

    private fun renderChildren(): String {
        val builder = StringBuilder()
        children.forEach { child ->
            builder.append(child.toString())
        }
        return builder.toString()
    }
}

fun main() {
    val htmlDoc = html {
        set("lang", "en")
        add(Tag("head") {
            add(Tag("title") {
                + "Page Title"
            })
        })
        add(Tag("body") {
            add(Tag("h1") {
                + "Hello, World!"
            })
            add(Tag("p") {
                + "This is a paragraph."
            })
        })
    }
    println(htmlDoc)
}

고차 함수를 사용하여

  HTML 문서 작성을 위한 도메인별 언어(DSL)를 정의하는 방법을 보여줍니다.

html() 함수는

  HTML 문서의 내용을 정의하는 람다 식을 사용하고 문서의 문자열 표현을 반환합니다.

 

Tag 클래스는

  HTML 태그를 나타내며

    특성을 설정하고 하위 태그를 추가하기 위한 메서드를 제공합니다.

 

set() 메서드는

  속성의 이름과 값을 가져와 태그의 속성 맵에 추가하고,

add() 메서드는

  자식 태그를 가져와 태그의 자식 목록에 추가합니다.

 

속성 및 자식을 포함하여 태그의 문자열 표현을 생성하도록

  toString() 메서드를 재정의합니다.

renderAttributes() renderChildren() 메서드는

  각각 태그 속성 및 자식의 문자열 표현을 생성하는 데 사용됩니다.

 

main() 함수에서

  DSL을 사용하여 제목 태그가 포함된 헤드 섹션과 h1 태그 및 p 태그가 포함된 본문 섹션이 있는 HTML 문서를 정의합니다.

 

+ 연산자는

  태그에 텍스트 콘텐츠를 추가하는 데 사용됩니다.

 

main() 함수의 출력은

  웹 브라우저에서 렌더링 할 수 있는 HTML 문서의 문자열 표현입니다.

 

그냥 사용을 위한 예시를 가져와봤습니다.

이렇게 쓰는 사람이 있을까 궁금하긴 합니다.

 


 

요약

전반적으로 고차 함수는

  유지 관리 및 확장이 더 쉽고

    더 간결하고 표현력이 풍부하며

      유연한 코드를 작성하는 데 도움이 되는 강력한 도구입니다.

Kotlin 언어의 이 기능을 활용하면

  더 모듈화 되고 재사용 가능하며 다양한 사용 사례에 적응할 수 있는 코드를 만들 수 있습니다.

 


 

'Kotlin' 카테고리의 다른 글

코루틴  (0) 2023.02.16
@EventListener  (0) 2023.02.14

댓글