12 함수형 프로그래밍과 람다

함수형 프로그래밍의 정의

변수(할당) 없는 프로그래밍

순수 함수로 정의되는 함수

  • 순수함수는 Side-effect가 발생하지 않는다
  • 함수 외부의 다른 값을 변경하지 않음
  • 내부에서 별도의 I/O가 발생하지 않음
  • 동일 입력 동일 출력

프로그래밍 패러다임

  • 절차지향

    • 알고리즘과 로직 중심으로 문제 해결
  • 객체지향 프로그래밍

    • 기능과 데이터를 묶어 객체를 만들고 조합하는 프로그래밍
  • 함수형 프로그래밍

    • 함수의 선언과 선언된 함수의 유기적인 흐름
  • 왜 함수형 프록래밍이 대두되는가

    • 복잡성 증가
    • 디버깅
    • 동시성 프로그래밍

함수형에서의 데이터

  • 데이터는 변경되지 않으며 프로그램의 상태만 표현(immutable state data)
  • 데이터는 변경하는 것이 아니라 새로운 데이터를 만들어 리턴

장점

  • 간결한 코드 -> 유지보수성 증대
  • 안전한 동시성 프로그래밍 -> 부수효과가 없음

원칙

일급객체(First class citizen)

  • 프로그램 top-level에 함수를 정의
  • 모든 구성요소를 함수 안에 작성
  • 함수를 변수처럼 이용

코틀린에서

다양한 구성요소를 포함

함수 내에 변수, class, 함수 등 모든 요소를 포함 가능

변수처럼 이용하는 함수

// 람다 표현식
val foo = { bar: Int ->
    println("hello world")
    bar + 10
}
foo(5)
// reflection
val foo = { bar: Int ->
    println("hello world")
    bar + 10
}

val bar = ::foo

람다 표현식

  • 익명함수(anonymous function)
  • 마지막 표현식을 리턴
fun sum(a: Int, b: Int): Int {
    return a + b
}
val sum = {a: Int, b: Int -> a + b }

즉시실행함수

{ println("hello") }()
run { println("hello") }

매개변수가 없는 람다함수

val foo = { -> 10 + 20 }
val bar = { 10 + 20 }

함수 타입

  • 타입을 명시하면 파라미터 타입을 명시하지 않아도 됨
fun sum(a: Int, b: Int): Int {
    return a + b
}

val foo: (Int, Int) -> Int = { a: Int, b: Int -> a + b }
val bar: (Int, Int) -> Int = { a, b -> a + b }

typealias를 이용한 타입 정의

typealias MyType = (Int) -> Boolean

val foo: MyType = { it > 10 }

it을 이용한 매개변수 이용

  • 매개변수가 하나인 경우, it으로 매개변수 지칭
val foo: (Int) -> Int = { x -> x + 2 }
val bar: (Int) -> Int = { it + 2 }

val bax = { it + 2 } // error, it의 타입이 명시되지 않아서

멤버 참조

  • Member reference는 (::)로 표현
class User(val name: String, val age: Int)

val bar: (User) -> String = { u: User -> u.name }
val foo: (User) -> String = User::name