-
[코틀린리액티브] 02.코틀린과 RxKotlin 을 사용한 함수형 프로그래밍읽고있는책 2020. 5. 15. 12:14
함수형 프로그래밍의 정의로 시작한다.
이 책은 정의를 먼저 언급하고 예시와 비교를 통해 추가 설명해주는 과정이 너무 좋다.
함수형 프로그래밍은 작고 재사용 가능한 선언적인 함수의 사용을 권장하는 선언적인 프로그래밍 패러다임이다.
함수형 리액티브 프로그래밍은 리액티브 프로그래밍과 함수형 프로그래밍을 혼합한 개념이다. 함수형 프로그래밍의 목적은 쉽게 모듈화가 가능한 프로그램을 구현하는 것이다. 모듈화된 프로그램은 반응형 프로그래밍을 구현하거나 필요에 따라 리액티브 선언문의 네 가지 원칙을 구현하는 데 필요하다.
좋은 정의다. 그냥 좋기만 하다. 아직은 이해할 수가 없다. 세부적인 내용들을 공부하면서 위 정의를 제대로 이해해보자.
일단 함수형 프로그래밍의 정의를 기준으로 세부적인 내용을 봐보자.
함수형 프로그래밍에 대한 세부적인 내용으로 5가지를 볼 수 있다.
람다, 순수함수, 고차함수, 함수유형, 인라인 함수
(람다와 순수함수가 동일한 것으로 인식하는 개발자가 많지만, 그렇지 않다고 한다. 난 그냥 아 그렇구나 하고 넘어간다... )
버전차이로 지금 없어진 문법이 너무 많다! 그냥 그런가보다 하고 보고 넘어가는 게 좋을듯...
람다
람다는 일반적으로 이름이 없는 익명함수를 의미한다. 람다는 함수이지만, 모든 함수가 람다는 아니다.(오...)
코틀린에서 람다가 작동하는 방식을 보자.
fun main(args: Array<String>){ val sum = { x: Int, y: Int -> x+y} println("Sum ${sum(12,14)}") val anonymousMult = { x:Int -> ((0..15).random() + 1) * x} println("Random output ${anonymousMult(2)}") }두 개의 람다식을 통해 익명함수를 사용하는 것을 볼 수 있다.
순수 함수
순수함수의 정의는 함수의 반환값이 인수/매개 변수에 전적으로 의존하는 함수를 말한다.
(원래 다 함수가 그런거 아닌가? 라는 생각이 들었다. 위에 두 개의 람다를 보면 첫번째 람다는 값이 고정되어 있지만, 두번째 람다는 랜덤값 때문에 실행 때 마다 결과값이 달라진다. 그래서 두번째 람다는 순수 함수가 될 수 없다.)
예제를 하나 더 보자.
fun main(args: Array<String>){ println("named pure func square = ${square(3)}") val qube = { n:Int -> n*n*n } println("lambda pure func qube = ${qube(3)}") } fun square(n:Int) : Int{ return n*n }두 개의 순수함수가 쓰였다. 다만 세부적으로 보면 square 는 이름이 있는 함수, qube 는 람다일 뿐이다.
언제나 동일한 값을 반환하는 순수함수로서의 정의를 만족한다.
고차함수
고차함수는 함수를 인자로 받거나 반환하는 함수를 말한다. 말이 어렵지 보면 바로 그냥 아~ 한다.
fun highOrderFunc (a: Int, validityCheckFunc:(a:Int) -> Boolean) { if(validityCheckFunc(a)) { println("a $a is Valid") } else { println("a $a is Invalid") } } fun main(args: Array<String>) { highOrderFunc(12, { a:Int -> a.isEven()}) highOrderFunc(19, { a:Int -> a.isEven()}) }인라인함수
예제부터 보자.
fun doSomeStuff (a: Int = 0) = a + (a*a) fun main(args: Array<String>) { for (i in 1..10) { println(" $i Output ${doSomeStuff(i)}") } }간단한 로직이다. 우리가 로직을 짤 때는 큰 문제가 없으나, 내부적으로 메모리 최적화를 저하시킬 수 있다고 한다. 위의 코드는 두개의 숫자를 더하고 그 결과를 반환하는 함수를 선언하고, 루프에서 함수를 호출하는 구조이다.
이 구조를 함수를 선언하는 방식이 아닌, 호출되는 곳에 바로 덧셈을 수행하는 로직을 작성한다면 함수의 호출, 스택에서 많은 메모리를 쓰지 않게 될 것이다. (사실 예제에서는 그리 많은 스택이 있진 않은 것 같지만 어떤 의미인지는 이해가 간다.)
이를 인라인으로 선언하면 다음과 같다.
inline fun doSomeStuff (a: Int = 0) = a + (a*a) fun main(args: Array<String>) { for (i in 1..10) { println(" $i Output ${doSomeStuff(i)}") } }함수 선언 앞에 inline 붙여준 게 전부다. 이렇게 쓰면 함수 호출하는 곳에 덧셈로직이 있는 것처럼 실행이 된다. 컴파일 시 자세한 내용은 언급하지 않고 결과적인 부분만 쓰겠다.
정말 간단하게 코틀린에서의 함수 사용법을 다뤘다. 일단 책의 첫 부분이기 때문에 간단하게 언급하고 넘어가는 것 같다.
상세한 내용은 코틀린 래퍼런스를 통해 학습해야 한다.
코루틴
갑자기 코루틴을 언급하는게 조금은 당황스럽지만 코루틴에 대해 다루고 있다. 설명도 조금...부족하다.
첨부된 링크를 통해 이해하고 넘어가는 것을 추천.
역시나 정의를 먼저 이야기한다.
코루틴은 쓰레드와 같이 비동기식, 논블로킹 코드를 작성하는 새로운 방법이지만 더 간단하고 효율적이며 경량의 솔루션이다.
RxKotlin 에서는 아직 코루틴을 사용하지 않는다. (이런 글을 남기는 건 조금 위험지만.... 이 글을 읽을 땐 어? 쓰는데? 할 수 있으니 그냥 넘어가주시면 될듯). 아직 사용하지 않는 이유는 코루틴과 RxKotlin 스케쥴러의 내부 구조가 동일하기 때문이라고 한다.
코루틴의 의존성을 추가하는 부분은 ... 넘어가겠다.
suspend fun longRunningTask(): Long { val time = measureTimeMillis { println("Please Wait") delay(2, TimeUnit.SECONDS) println("Delay Over") } return time } fun main(args: Array<String>) { runBlocking { val exeTime = longRunningTask() println(" Execution Time is $exeTime") } }suspend 는 함수를 일시중지로 표시하는 키워드이다. 간단하게 메인 함수가 실행되면서 딜레이가 되는 걸 기다리게 되는 로직이다.
기다리지 않게 작업한다면 어떻게 표현할 수 있을까?
suspend fun longRunningTask(): Long { val time = measureTimeMillis { println("Please Wait") delay(2, TimeUnit.SECONDS) println("Delay Over") } return time } fun main(args: Array<String>) { val time = async(CommonPool) { longRunningTask()} println( "Print after async") runBlocking { println("printing time ${time.await()}")} }여기서 특이한 점은 time 변수가 사용가능해질 때까지 기다리게 할 수 있다는 점이다.
처음 읽었을 땐 무슨 말이지 싶었는데, 기다리는 주체가 다르다. 위는 메인 스레드가 기다리고, 아래는 async 쓰레드가 기다린다.
좀 더 구체적인 예제를 보자. 피보나치 수열을 구현할 것이다. 기존에 구현하는 방식을 보자. 완벽한 피보나치는 아니고, 앞부분만?
fun main(args: Array<String>) { var a = 0 var b = 1 print("$a, ") print("$b, ") for(i in 2..9){ val c = a+b print("$c, ") a=b b=c } }이를 코루틴을 이용해보자.
fun main(args: Array<String>) { val fibonacciSeries = buildSequence { var a = 0 var b = 1 yield(a) yield(b) while(true){ val c = a+b yield(c) a=b b=c } } println(fibonacciSeries.take(10) join ",") }이렇게 나오고 설명이 나와있는데 설명이 진짜 이해가 1도 안된다.
뭐 이런 식으로 표현했지 싶지만, 이 책은 코틀린 초보자를 위한 책이 아니다. 반성하고 코루틴 설명 페이지를 보자.
나는 이 페이지를 읽어보았다. https://medium.com/@jooyunghan/%EC%BD%94%EB%A3%A8%ED%8B%B4-%EC%86%8C%EA%B0%9C-504cecc89407
코루틴 소개
코루틴은 suspend/resume 가능하다. 함수가 call/return되는 것과 비교하면 더 일반화된 형태라 할 수 있다. (함수는 suspend/resume이 빠진 코루틴인 셈이다.)
medium.com
코루틴 설명이 약간 아쉽지만, 링크된 페이지로 이해하는 것으로 하고,(함수)
다음 모나드라는 부분이 나왔다.
모나드
정의, 모나드는 값을 캡슐화하고 추가 기능을 더해 새로운 타입을 생성하는 구조체 라고 한다.
역시나 모르겠다. Maybe 라는 것이 나오는데 타입 중에 하나인 듯하다.
구독을 하고 onComlete, onError, OnSuccess 를 호출한다. 역시나 설명이 불충분하다.
모나드에 대한 정의를 살펴보면, 추상적인 내용이고 이 책에서는 극히 일부만을 다룬 것으로 보인다. 일단은 넘어가야 겠다.사실 잘 모르겠다.
반응형'읽고있는책' 카테고리의 다른 글
[코틀린리액티브] 03. 옵저버블과 옵저버와 구독자 (0) 2020.05.16 [코틀린리액티브] 01. 리액티브 프로그래밍 소개 (0) 2020.05.15