SlideShare une entreprise Scribd logo
1  sur  285
Télécharger pour lire hors ligne
Functional
Programming
Lazysoul

우명인
FP?
• Immutable DataStructure

• Pure Function

• Lazy evaluation
• Immutable DataStructure
FP?
• Immutable DataStructure
FP?
var mutableInt: Int = 10
mutableInt = 5
var mutableString: String = "FP"
mutableString = "Kotlin"
• Immutable DataStructure
FP?
var mutableInt: Int = 10
mutableInt = 5
var mutableString: String = "FP"
mutableString = "Kotlin"
property keyword
• Immutable DataStructure
FP?
var mutableInt: Int = 10
mutableInt = 5
var mutableString: String = "FP"
mutableString = "Kotlin"
property name
• Immutable DataStructure
FP?
var mutableInt: Int = 10
mutableInt = 5
var mutableString: String = "FP"
mutableString = "Kotlin"
property type
• Immutable DataStructure
FP?
var mutableInt: Int = 10
mutableInt = 5
var mutableString: String = "FP"
mutableString = "Kotlin"
property value
• Immutable DataStructure
FP?
var mutableInt: Int = 10
mutableInt = 5
var mutableString: String = "FP"
mutableString = "Kotlin"
• Immutable DataStructure
FP?
val immutableInt: Int = 10
immutableInt = 5 // Error
val immutableString: String = "FP"
immutableString = "Kotlin" // Error
• Immutable DataStructure
FP?
var mutableList: MutableList<Int> = mutableListOf(1, 2, 3)
mutableList.add(10)
• Immutable DataStructure
FP?
var mutableList: MutableList<Int> = mutableListOf(1, 2, 3)
mutableList.add(10)
println(mutableList) // [1, 2, 3, 10]
• Immutable DataStructure
FP?
val immutableList: List<Int> = listOf(1, 2, 3)
immutableList.add(10) // Error
println(immutableList) // [1, 2, 3]
• Immutable DataStructure
FP?
val immutableList: List<Int> = listOf(1, 2, 3)
immutableList.add(10) // Error
println(immutableList) // [1, 2, 3]
immutableList.plus(10)
• Immutable DataStructure
FP?
val immutableList: List<Int> = listOf(1, 2, 3)
immutableList.add(10) // Error
println(immutableList) // [1, 2, 3]
immutableList.plus(10)
println(immutableList) // [1, 2, 3]
• Immutable DataStructure
FP?
val immutableList: List<Int> = listOf(1, 2, 3)
immutableList.add(10) // Error
println(immutableList) // [1, 2, 3]
immutableList.plus(10)
println(immutableList) // [1, 2, 3]
println(immutableList.plus(10)) // [1, 2, 3, 10]
• Immutable DataStructure
FP?
val immutableList: List<Int> = listOf(1, 2, 3)
immutableList.add(10) // Error
println(immutableList) // [1, 2, 3]
immutableList.plus(10)
println(immutableList) // [1, 2, 3]
println(immutableList.plus(10)) // [1, 2, 3, 10]
val newList = immutableList.plus(10)
• Immutable DataStructure
FP?
val immutableList: List<Int> = listOf(1, 2, 3)
immutableList.add(10) // Error
println(immutableList) // [1, 2, 3]
immutableList.plus(10)
println(immutableList) // [1, 2, 3]
println(immutableList.plus(10)) // [1, 2, 3, 10]
val newList = immutableList.plus(10)
println(immutableList) // [1, 2, 3]
println(newList) // [1, 2, 3, 10]
• Pure Function
FP?
• Pure Function
FP?
fun main(args: Array<String>) {
println(pureFunction("FP")) // Hello FP
}
fun pureFunction(input: String): String {
return "Hello " + input
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(pureFunction("FP")) // Hello FP
println(pureFunction("FP")) // Hello FP
println(pureFunction("FP")) // Hello FP
}
fun pureFunction(input: String): String {
return "Hello " + input
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(nonPureFunction("FP")) // Hello FP
}
val strBuilder: StringBuilder = StringBuilder("Hello ")
fun nonPureFunction(input: String): String {
return strBuilder.append(input).toString()
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(nonPureFunction("FP")) // Hello FP
}
val strBuilder: StringBuilder = StringBuilder("Hello ")
fun nonPureFunction(input: String): String {
return strBuilder.append(input).toString()
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(nonPureFunction("FP")) // Hello FP
println(nonPureFunction("FP")) // Hello FPFP
println(nonPureFunction("FP")) // Hello FPFPFP
}
val strBuilder: StringBuilder = StringBuilder("Hello ")
fun nonPureFunction(input: String): String {
return strBuilder.append(input).toString()
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(nonPureFunction2(4)) // 5
}
var x = 1
fun nonPureFunction2(input: Int): Int{
return input + x
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(nonPureFunction2(4)) // 5
}
var x = 1
fun nonPureFunction2(input: Int): Int{
return input + x
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(nonPureFunction2(4)) // 5
println(nonPureFunction2(4)) // 5
println(nonPureFunction2(4)) // 5
}
var x = 1
fun nonPureFunction2(input: Int): Int{
return input + x
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(nonPureFunction2(4)) // 5
println(nonPureFunction2(4)) // 5
println(nonPureFunction2(4)) // 5
x = 10
}
var x = 1
fun nonPureFunction2(input: Int): Int{
return input + x
}
• Pure Function
FP?
fun main(args: Array<String>) {
println(nonPureFunction2(4)) // 5
println(nonPureFunction2(4)) // 5
println(nonPureFunction2(4)) // 5
x = 10
println(nonPureFunction2(4)) // 14
}
var x = 1
fun nonPureFunction2(input: Int): Int{
return input + x
}
• Lazy evaluation
FP?
• Lazy evaluation
FP?
val lazyValue: String by lazy {
println("시간이 오래 걸리는 작업")
"hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
• Lazy evaluation
FP?
val lazyValue: String by lazy {
println("시간이 오래 걸리는 작업")
"hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
시간이 오래 걸리는 작업
hello
hello
• Lazy evaluation
FP?
val lazyValue: String by lazy {
println("시간이 오래 걸리는 작업")
"hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
시간이 오래 걸리는 작업
hello
hello
• Lazy evaluation
FP?
val infiniteValue = generateSequence(0) { it + 1 }
infiniteValue
.take(5)
.forEach { print("$it ") }
• Lazy evaluation
FP?
val infiniteValue = generateSequence(0) { it + 1 }
infiniteValue
.take(5)
.forEach { print("$it ") } //0 1 2 3 4
• Lazy evaluation
FP?
val lazyValue2: () -> Unit = {
println("FP")
}
lazyValue2
lazyValue2
lazyValue2
lazyValue2()
• Lazy evaluation
FP?
val lazyValue2: () -> Unit = {
println("FP")
}
lazyValue2 //
lazyValue2 //
lazyValue2 //
lazyValue2() // FP
Functional
Data Structure
Functional Data Structure
• control with pure functions

• Immutable Data Structure

• Data Share
Functional Data Structure
fun main(args: Array<String>) {
val value = 3
val result = plusThree(value)
}
fun plusThree(x: Int): Int {
return x + 3
}
Functional Data Structure
fun main(args: Array<String>) {
val value = 3
val result = plusThree(value)
println(result) // 6
println(value) // 3
}
fun plusThree(x: Int): Int {
return x + 3
}
Functional Data Structure
fun main(args: Array<String>) {
val list = listOf(1, 2)
val listResult = plusThree(list)
}
fun plusThree(list: List<Int>): List<Int> {
return list.plus(3)
}
Functional Data Structure
fun main(args: Array<String>) {
val list = listOf(1, 2)
val listResult = plusThree(list)
println(list) // [1, 2]
println(listResult) // [1, 2, 3]
}
fun plusThree(list: List<Int>): List<Int> {
return list.plus(3)
}
Functional Data Structure
• Data Share
Functional Data Structure
• Data Share
val list = listOf(1, 2)
Functional Data Structure
• Data Share
val list = listOf(1, 2)
1 2
Cons Cons
Head Tail Head Tail
NIL
list
Functional Data Structure
• Data Share
val list = listOf(1, 2)
val listResult = plusThree(list)
1 2
Cons Cons
Head Tail Head Tail
list
NIL
Functional Data Structure
• Data Share
fun plusThree(list: List<Int>): List<Int> {
return list.plus(3)
}
Tail NIL1 2
Head Tail Head Tail
NIL
list
Functional Data Structure
• Data Share
list
fun plusThree(list: List<Int>): List<Int> {
return list.plus(3)
}
Tail 3
Cons
Head Tail
NIL1 2
Head Tail Head Tail
1 2
Head Tail Head Tail
NIL
list
• Data Share
Functional Data Structure
• Data Share
1 2
Cons Cons
Head Tail Head Tail
3
Cons
Head Tail
NIL
val listResult = plusThree(list)
listResult
Functional Data Structure
val tail = listResult.tail()
• Data Share
Functional Data Structure
val tail = listResult.tail()
• Data Share
1 2
Cons Cons
Head Tail Head Tail
listResult
3
Cons
Head Tail
NIL
Tail
Functional Data Structure
val tail = listResult.tail()
• Data Share
2
Cons
Head Tail
3
Cons
Head Tail
NIL
Tail
Recursion
Recursion
• solutions to smaller instances of the same problem
Recursion
• solutions to smaller instances of the same problem
Recursion
• Tip

• 어떻게 보다 무엇에 집중.

• 종료조건부터 생각하자.

• 재귀를 반복 할수록 종료 조건으로 수렴.
Recursion
fun factorial(num: Int): Int {
var result = 1
for (i in 1..num) {
result *= i
}
return result
}
Recursion
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
Recursion
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
Readability +
Recursion
n * factorial2( n-1)
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
Recursion
n * factorial2( n-1)
n * (n-1 * factorial2(n -2) )
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
Recursion
n * factorial2( n-1)
n * (n-1 * factorial2(n -2) )
n * (n-2 * (n-3 * factorial2(n-3)))
n * (n-2 * (n-3 * (n-4 * factorial2(n-4))))
….. ((((((1))))))
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
Recursion
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
n * factorial2( n-1)
n * (n-1 * factorial2(n -2) )
n * (n-2 * (n-3 * factorial2(n-3)))
n * (n-2 * (n-3 * (n-4 * factorial2(n-4))))
….. ((((((1))))))
n * (n-2 * (n-3 * (n-4 * 1)))
n * (n-2 * (n-3 * n-4 * 1))
n * (n-2 * n-3 * n-4 * 1)
n * n-2 * n-3 * n-4 * 1
Recursion
5 * factorial2(4)
5 * (4 * factorial2(3))
5 * (4 * (3 * factorial2(2)))
5 * (4 * (3 * (2 * factorial2(1))))
5 * (4 * (3 * (2 * (1))))
5 * (4 * (3 * (2)))
5 * (4 * (6))
5 * (24)
120
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
Recursion
5 * factorial2(4)
5 * (4 * factorial2(3))
5 * (4 * (3 * factorial2(2)))
5 * (4 * (3 * (2 * factorial2(1))))
5 * (4 * (3 * (2 * (1))))
5 * (4 * (3 * (2)))
5 * (4 * (6))
5 * (24)
120
Performance -
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
Recursion
5 * factorial2(4)
5 * (4 * factorial2(3))
5 * (4 * (3 * factorial2(2)))
5 * (4 * (3 * (2 * factorial2(1))))
5 * (4 * (3 * (2 * (1))))
5 * (4 * (3 * (2)))
5 * (4 * (6))
5 * (24)
120
Performance -
SOF
fun factorial2(num: Int): Int = when (num) {
1 -> 1
else -> num * factorial2(num - 1)
}
Recursion
• Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀
로 구현하자
Recursion
• Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀
로 구현하자
종료조건?
Recursion
• Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀
로 구현하자
fun getMaxValue(list: List<Int>): Int = when {
list.isEmpty() -> throw NullPointerException()
list.size == 1 -> list.first()
}
종료조건?
Recursion
• Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀
로 구현하자
fun getMaxValue(list: List<Int>): Int = when {
list.isEmpty() -> throw NullPointerException()
list.size == 1 -> list.first()
}
종료 조건으로 수렴?
Recursion
• Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀
로 구현하자
fun getMaxValue(list: List<Int>): Int = when {
list.isEmpty() -> throw NullPointerException()
list.size == 1 -> list.first()
else -> if (list.first() > getMaxValue(list.drop(1))) {
list.first()
} else {
getMaxValue(list.drop(1))
}
}
종료 조건으로 수렴?
Recursion
tailrec fun factorial3(num: Int, acc: Int = 1): Int =
when (num) {
1 -> acc
else -> factorial3(num - 1, acc * num)
}
Recursion
tailrec fun factorial3(num: Int, acc: Int = 1): Int =
when (num) {
1 -> acc
else -> factorial3(num - 1, acc * num)
}
• TailRecursion
Recursion
tailrec fun factorial3(num: Int, acc: Int = 1): Int =
when (num) {
1 -> acc
else -> factorial3(num - 1, acc * num)
}
factorial3( n-1, n)
• TailRecursion
Recursion
tailrec fun factorial3(num: Int, acc: Int = 1): Int =
when (num) {
1 -> acc
else -> factorial3(num - 1, acc * num)
}
factorial3( n-1, n)
factorial3( n-2, acc * n-1)
factorial3( n-3, acc * n-2)
• TailRecursion
Recursion
tailrec fun factorial3(num: Int, acc: Int = 1): Int =
when (num) {
1 -> acc
else -> factorial3(num - 1, acc * num)
}
factorial3( n-1, n)
factorial3( n-2, acc * n-1)
factorial3( n-3, acc * n-2)
…
factorial3( 1, acc ….)
acc
• TailRecursion
Recursion
tailrec fun factorial3(num: Int, acc: Int = 1): Int =
when (num) {
1 -> acc
else -> factorial3(num - 1, acc * num)
}
Readability +
• TailRecursion
Recursion
tailrec fun factorial3(num: Int, acc: Int = 1): Int =
when (num) {
1 -> acc
else -> factorial3(num - 1, acc * num)
}
Readability +
Performance +
• TailRecursion
Recursion
tailrec fun factorial3(num: Int, acc: Int = 1): Int =
when (num) {
1 -> acc
else -> factorial3(num - 1, acc * num)
}
Readability +
Performance +
!SOP
Recursion
• 연습문제 (exercise1)

• getMaxValue를 꼬리 재귀로 만들어보자.
Recursion
• 연습문제 (exercise1)

• getMaxValue를 꼬리 재귀로 만들어보자.
tailrec fun getMaxValue(list: List<Int>, acc: Int): Int =
when {
list.isEmpty() -> throw NullPointerException()
list.size == 1 -> acc
else -> if (list.first() >= acc) {
getMaxValue(list.drop(1), list.first())
} else {
getMaxValue(list.drop(1), acc)
}
}
Recursion
• 연습문제 (exercise1)

• getMaxValue를 꼬리 재귀로 만들어보자.
tailrec fun getMaxValue(list: List<Int>, acc: Int): Int =
when {
list.isEmpty() -> throw NullPointerException()
list.size == 1 -> acc
else -> if (list.first() >= acc) {
getMaxValue(list.drop(1), list.first())
} else {
getMaxValue(list.drop(1), acc)
}
}
종료조건
Recursion
• 연습문제 (exercise1)

• getMaxValue를 꼬리 재귀로 만들어보자.
tailrec fun getMaxValue(list: List<Int>, acc: Int): Int =
when {
list.isEmpty() -> throw NullPointerException()
list.size == 1 -> acc
else -> if (list.first() >= acc) {
getMaxValue(list.drop(1), list.first())
} else {
getMaxValue(list.drop(1), acc)
}
} 종료조건으로 수렴하는 로직
Function Type
Function Type
val functionType: () -> Unit
Function Type
val functionType: () -> Unit
Input
Function Type
val functionType: () -> Unit
Input
Output
Function Type
val functionType: () -> Unit
val functionType1: (Int) -> Unit
val functionType2: (Int, String) -> Unit
Function Type
val functionType: () -> Unit
val functionType1: (Int) -> Unit
val functionType2: (Int, String) -> Unit
functionType = { println("FP") }
functionType1 = { value -> println(value.toString()) }
functionType2 = { intValue, stringValie ->
println("intValue $intValue, stringValue $stringValie")
}
Function Type
val functionType: () -> Unit
val functionType1: (Int) -> Unit
val functionType2: (Int, String) -> Unit
functionType = { println("FP") }
functionType1 = { value -> println(value.toString()) }
functionType2 = { intValue, stringValie ->
println("intValue $intValue, stringValue $stringValie")
}
functionType() // FP
functionType1(10) // 10
functionType2(10, "FP") // intValue 10, stringVAlue FP
• 연습문제 2: 

• Int 타입 2개를 입력받아서, 입력받은 두 값을 곱한 결과 값 을
반환하는 함수타입 프로퍼티 product를 만들어 보자.
Function Type
• 연습문제 2: 

• Int 타입 2개를 입력받아서, 입력받은 두 값을 곱한 결과 값 을
반환하는 함수타입 프로퍼티 product를 만들어 보자.

• 연습문제 2: 

• String 타입 3개를 입력받아서, 하나의 스트링으로 합쳐주는 함
수타입 프로퍼티 appendStrings 를 만들어보자.
Function Type
First Class Citizen
• Pass a function as an Argument

• Return a function

• Assign a function to a data structure
First Class Citizen
• Pass a function as an Argument
First Class Citizen
fun function(param: () -> Unit) {
// something
}
• Return a function
First Class Citizen
fun function2(): () -> Unit {
return { println("FP") }
}
• Assign a function to a data structure
First Class Citizen
val value1: () -> Unit = { println("FP") }
• Assign a function to a data structure
First Class Citizen
val value1: () -> Unit = { println("FP") }
val value2: List<() -> Unit> = listOf({ println("FP") })
• Assign a function to a data structure
First Class Citizen
val value1: () -> Unit = { println("FP") }
val value2: List<() -> Unit> = listOf({ println("FP") })
val value3: Map<String, () -> Unit> =
mapOf("FP" to { println("FP") })
Higher-order function
Higher-order function
• Pass a function as an Argument

• Return a function

• Pass a function as an Argument OR Return a function
Higher-order function
• Pass a function as an Argument
Higher-order function
• Pass a function as an Argument
fun higherOrderFunction1(func: () -> Unit) {
func()
}
Higher-order function
• Pass a function as an Argument
fun higherOrderFunction1(func: () -> Unit) {
func()
}
Higher-order function
• Return a function
Higher-order function
• Return a function
fun higherOrderFunction2(): () -> Unit {
return { println("FP") }
}
Higher-order function
• Return a function
fun higherOrderFunction2(): () -> Unit {
return { println("FP") }
}
Higher-order function
• Pass a function as an Argument OR Return a function
Higher-order function
• Pass a function as an Argument OR Return a function
fun higherOrderFunction1(func: () -> Unit) {
func()
}
fun higherOrderFunction2(): () -> Unit {
return { println("FP") }
}
fun higherOrderFunction3(func: () -> Unit): () -> Unit {
return func
}
CallByName
CallByName
fun callByName(): () -> String = {
println("callByName")
// shomething
"callByName"
}
CallByName
fun callByName(): () -> String = {
println("callByName")
// shomething
"callByName"
}
fun callByValue(): String {
println("callByValue")
return "callByValue"
}
CallByName
fun main(args: Array<String>) {
callByName() // ""
callByValue() // "callByValue"
}
fun callByName(): () -> String = {
println("callByName")
// shomething
"callByName"
}
fun callByValue(): String {
println("callByValue")
return "callByValue"
}
CallByName
fun main(args: Array<String>) {
callByName() // ""
callByValue() // "callByValue"
}
fun callByName(): () -> String = {
println("callByName")
// shomething
"callByName"
}
fun callByValue(): String {
println("callByValue")
return "callByValue"
}
CallByName
fun main(args: Array<String>) {
callByName() // ""
callByValue() // "callByValue"
}
fun callByName(): () -> String = {
println("callByName")
// shomething
"callByName"
}
fun callByValue(): String {
println("callByValue")
return "callByValue"
}
CallByName
fun main(args: Array<String>) {
callByName()() // "callByName"
callByValue() // "callByValue"
}
fun callByName(): () -> String = {
println("callByName")
// shomething
"callByName"
}
fun callByValue(): String {
println("callByValue")
return "callByValue"
}
CallByName
개념은 알겠는데... 그래서??
CallByName
fun doCallByName(condtion: Boolean, callByName: () -> String) {
if (condtion) {
callByName()
}
}
fun doCallByValue(condtion: Boolean, callByValue: String) {
if (condtion) {
callByValue
}
}
CallByName
fun doCallByName(condtion: Boolean, callByName: () -> String) {
if (condtion) {
callByName()
}
}
fun doCallByValue(condtion: Boolean, callByValue: String) {
if (condtion) {
callByValue
}
}
CallByName
fun doCallByName(condtion: Boolean, callByName: () -> String) {
if (condtion) {
callByName()
}
}
fun doCallByValue(condtion: Boolean, callByValue: String) {
if (condtion) {
callByValue
}
}
CallByName
fun doCallByValue(condtion: Boolean, callByValue: String) {
if (condtion) {
callByValue
}
}
fun callByValue(): String {
println("callByValue")
return "FP"
}
doCallByValue(true, callByValue())
// "callByValue"
CallByName
fun doCallByValue(condtion: Boolean, callByValue: String) {
if (condtion) {
callByValue
}
}
fun callByValue(): String {
println("callByValue")
return "FP"
}
doCallByValue(true, callByValue())
// "callByValue"
doCallByValue(false, callByValue())
// "callByValue"
CallByName
fun doCallByName(condtion: Boolean, callByName: () -> String) {
if (condtion) {
callByName()
}
}
fun callByName(): () -> String = {
println("callByName")
// shomething
"FP"
}
doCallByName(true, callByName())
// "callByName"
CallByName
fun doCallByName(condtion: Boolean, callByName: () -> String) {
if (condtion) {
callByName()
}
}
fun callByName(): () -> String = {
println("callByName")
// shomething
"FP"
}
doCallByName(true, callByName())
// "callByName"
doCallByName(false, callByName())
// ""
CallByName
• 함수의 값을 전달하지 않고 함수의 이름을 전달 할수 있다.
CallByName
• 함수의 값을 전달하지 않고 함수의 이름을 전달 할수 있다.

• 함수의 이름을 전달하면, 전달하는 시점에 함수가 실행되지 않는다.
CallByName
• 함수의 값을 전달하지 않고 함수의 이름을 전달 할수 있다.

• 함수의 이름을 전달하면, 전달하는 시점에 함수가 실행되지 않는다.

• 특정 상황에 따라 크고 무거운 연산을 하거나 하지 않을 경우 이름
에 의한 호출을 하면 훨씬 효율적이다.
CallByName
• 함수의 값을 전달하지 않고 함수의 이름을 전달 할수 있다.

• 함수의 이름을 전달하면, 전달하는 시점에 함수가 실행되지 않는다.

• 특정 상황에 따라 크고 무거운 연산을 하거나 하지 않을 경우 이름
에 의한 호출을 하면 훨씬 효율적이다.
게으른 연산(Lazy Evaluation)
Partial Applied
Function
Partial Applied Function
• Partial Applied Function

• Curring
Partial Applied Function
• Partial Applied Function
val func: (Int, Int) -> Int = { x, y -> x + y }
println(func(5, 10)) // 15
Partial Applied Function
• Partial Applied Function
val func: (Int, Int) -> Int = { x, y -> x + y }
println(func(5, 10)) // 15
x 값은 알고있지만 y는 나중에 알수 있다면??
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y는 나중에 알수 있다면??
fun <P1, P2, R> ((P1, P2) -> R).partialAppliedFunction(x: P1): (P2) -> R {
return { p2 -> this(x, p2) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y는 나중에 알수 있다면??
fun <P1, P2, R> ((P1, P2) -> R).partialAppliedFunction(x: P1): (P2) -> R {
return { p2 -> this(x, p2) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y는 나중에 알수 있다면??
fun <P1, P2, R> ((P1, P2) -> R).partialAppliedFunction(x: P1): (P2) -> R {
return { p2 -> this(x, p2) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y는 나중에 알수 있다면??
fun <P1, P2, R> ((P1, P2) -> R).partialAppliedFunction(x: P1): (P2) -> R {
return { p2 -> this(x, p2) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y는 나중에 알수 있다면??
val partial = func.partialAppliedFunction(5)
// doSomething
Partial Applied Function
• Partial Applied Function
val partial = func.partialAppliedFunction(5)
// doSomething
println(partial(10)) // 15
Partial Applied Function
• Partial Applied Function
val multiThree = { x: Int, y: Int, z: Int -> x * y * z }
println(multiThree(1, 2, 3)) // 6
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y, z 는 나중에 알수 있다면??
val multiThree = { x: Int, y: Int, z: Int -> x * y * z }
println(multiThree(1, 2, 3)) // 6
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y, z 는 나중에 알수 있다면??
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R {
return { p2, P3 -> this(x, p2, P3) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y, z 는 나중에 알수 있다면??
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R {
return { p2, P3 -> this(x, p2, P3) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y, z 는 나중에 알수 있다면??
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R {
return { p2, P3 -> this(x, p2, P3) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y, z 는 나중에 알수 있다면??
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R {
return { p2, P3 -> this(x, p2, P3) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y, z 는 나중에 알수 있다면??
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R {
return { p2, P3 -> this(x, p2, P3) }
}
Partial Applied Function
• Partial Applied Function
x 값은 알고있지만 y, z 는 나중에 알수 있다면??
val partial2 = multiThree.partialAppliedFunction(1)
println(partial2(2, 3)) // 6
• 연습문제 3: 

• 입력값 4개를 중 2개를 먼저 입력받고 나머지 2개는 나중에 받
는 (P1, P2, P3, P4) -> R의 확장함수 면서 부분 함수인
partialAppliedFunction을 만들자.

• Int값 4개를 입력받아서 모든 값을 더한 결과를 반환하는 함수타
입 프로퍼티 sumFour 를 만들자.

• sumFor에 partialAppliedFunction을 적용해보자.
Partial Applied Function
Partial Applied Function
• Curring
Partial Applied Function
• Curring
val multiThree = { x: Int, y: Int, z: Int -> x * y * z }
println(multiThree(1, 2, 3)) // 6
x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
Partial Applied Function
• Curring
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R =
{ p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } }
x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
Partial Applied Function
• Curring
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R =
{ p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } }
val curriedMultiThree = multiThree.curried()
println(curriedMultiThree(1)(2)(3)) // 6
x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
Partial Applied Function
• Curring
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R =
{ p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } }
val curriedMultiThree = multiThree.curried()
println(curriedMultiThree(1)(2)(3)) // 6
val p1 = curriedMultiThree(1)
// doSomething
x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
Partial Applied Function
• Curring
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R =
{ p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } }
val curriedMultiThree = multiThree.curried()
println(curriedMultiThree(1)(2)(3)) // 6
val p1 = curriedMultiThree(1)
// doSomething
val p2 = p1(2)
// doSomething
x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
Partial Applied Function
• Curring
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R =
{ p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } }
val curriedMultiThree = multiThree.curried()
println(curriedMultiThree(1)(2)(3)) // 6
val p1 = curriedMultiThree(1)
// doSomething
val p2 = p1(2)
// doSomething
val p3 = p2(3)
// doSomething
println(p3) //6
x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
Collection(Stream)
Collection(Stream)
• map

• filter

• drop

• dropWhile

• take

• groupBy

• fold, foldRight
Collection(Stream)
• map
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
Collection(Stream)
• map
val list = listOf(1, 2, 3, 4, 5, 6)
Collection(Stream)
• map
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.map { value -> value * value })
// [1, 4, 9, 16, 25, 36]
Collection(Stream)
• filter
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
return filterTo(ArrayList<T>(), predicate)
}
Collection(Stream)
• filter
val list = listOf(1, 2, 3, 4, 5, 6)
Collection(Stream)
• filter
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.filter { value -> value % 2 == 0 })
// [2, 4, 6]
Collection(Stream)
• drop
public fun <T> Iterable<T>.drop(n: Int): List<T> {
require(n >= 0) { "Requested element count $n is less than zero." }
if (n == 0) return toList()
val list: ArrayList<T>
if (this is Collection<*>) {
val resultSize = size - n
if (resultSize <= 0)
return emptyList()
if (resultSize == 1)
return listOf(last())
list = ArrayList<T>(resultSize)
if (this is List<T>) {
if (this is RandomAccess) {
for (index in n until size)
list.add(this[index])
} else {
for (item in listIterator(n))
list.add(item)
}
return list
}
}
else {
list = ArrayList<T>()
}
var count = 0
for (item in this) {
if (count++ >= n) list.add(item)
}
return list.optimizeReadOnlyList()
}
Collection(Stream)
• drop
val list = listOf(1, 2, 3, 4, 5, 6)
Collection(Stream)
• drop
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.drop(1))
// [2, 3, 4, 5, 6]
Collection(Stream)
• dropWhile
public inline fun <T> Iterable<T>.dropWhile(predicate: (T) -> Boolean): List<T> {
var yielding = false
val list = ArrayList<T>()
for (item in this)
if (yielding)
list.add(item)
else if (!predicate(item)) {
list.add(item)
yielding = true
}
return list
}
Collection(Stream)
• dropWhile
val list = listOf(1, 2, 3, 4, 5, 6)
Collection(Stream)
• dropWhile
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.dropWhile { value -> value < 3 })
// [3, 4, 5, 6]
Collection(Stream)
• filter vs dropWhile
Collection(Stream)
• filter vs dropWhile
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.filter { value -> value % 2 == 1 })
println(list.dropWhile { value -> value % 2 == 1 })
Collection(Stream)
• filter vs dropWhile
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.filter { value -> value % 2 == 1 })
// [1, 3, 5]
println(list.dropWhile { value -> value % 2 == 1 })
// [2, 3, 4, 5, 6]
Collection(Stream)
• take
public fun <T> Iterable<T>.take(n: Int): List<T> {
require(n >= 0) { "Requested element count $n is less than zero." }
if (n == 0) return emptyList()
if (this is Collection<T>) {
if (n >= size) return toList()
if (n == 1) return listOf(first())
}
var count = 0
val list = ArrayList<T>(n)
for (item in this) {
if (count++ == n)
break
list.add(item)
}
return list.optimizeReadOnlyList()
}
Collection(Stream)
• take
val list = listOf(1, 2, 3, 4, 5, 6)
Collection(Stream)
• take
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.take(3))
// [1, 2, 3]
Collection(Stream)
• groupBy
public inline fun <T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> {
return groupByTo(LinkedHashMap<K, MutableList<T>>(), keySelector)
}
Collection(Stream)
• groupBy
val list = listOf(1, 2, 3, 4, 5, 6)
Collection(Stream)
• groupBy
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.groupBy { value -> value % 2 })
// {1=[1, 3, 5], 0=[2, 4, 6]}
Collection(Stream)
• fold
public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
var accumulator = initial
for (element in this) accumulator = operation(accumulator, element)
return accumulator
}
Collection(Stream)
• fold
val list = listOf(1, 2, 3, 4, 5, 6)
Collection(Stream)
• fold
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.fold(0) { acc, value -> acc + value })
// 21
Collection(Stream)
• foldRight
public inline fun <T, R> List<T>.foldRight(initial: R, operation: (T, acc: R) -> R): R {
var accumulator = initial
if (!isEmpty()) {
val iterator = listIterator(size)
while (iterator.hasPrevious()) {
accumulator = operation(iterator.previous(), accumulator)
}
}
return accumulator
}
Collection(Stream)
• foldRight
val list = listOf(1, 2, 3, 4, 5, 6)
Collection(Stream)
• foldRight
val list = listOf(1, 2, 3, 4, 5, 6)
println(list.foldRight(0) { value, acc -> acc + value })
// 21
Collection(Stream)
• foldLeft vs foldRight
list1 = listOf("a", "b", "c", "d", "e", "f")
println(list1.foldRight("") { value, acc -> acc + value })
println(list1.fold("") { acc, value -> acc + value })
Collection(Stream)
• foldLeft vs foldRight
list1 = listOf("a", "b", "c", "d", "e", "f")
println(list1.foldRight("") { value, acc -> acc + value })
println(list1.fold("") { acc, value -> acc + value })
// abcdef
Collection(Stream)
• foldLeft vs foldRight
list1 = listOf("a", "b", "c", "d", "e", "f")
println(list1.foldRight("") { value, acc -> acc + value })
// fedcba
println(list1.fold("") { acc, value -> acc + value })
// abcdef
연습문제
• exercise4 파일에 있는 list와 collection api를 사용해서 새로운
list를 만들자.

• 나이가 30 이상이고, single 인 사람들의 이름을 반환
연습문제
• exercise4 파일에 있는 list와 collection api를 사용해서 새로운
list를 만들자.

• 나이가 30 이상이고, single 인 사람들의 이름을 반환
list.filter { person -> person.age > 30 }
.filter { person -> person.single }
.map { person -> person.name }
Algebraic Data Type
Algebraic Data Type
• ProductType / SumType

• Pattern Matching
Algebraic Data Type
interface RGBInterface
class Red : RGBInterface
class Green : RGBInterface
class Blue : RGBInterface
data class Dog(val name: String, val age: Int)
enum class RGB {
RED, GREEN, BLUE
}
sealed class Option<out T>
data class Just<T>(val value: T) : Option<T>()
object None : Option<Nothing>()
Algebraic Data Type
• ProductType
interface RGBInterface
class Red : RGBInterface
class Green : RGBInterface
class Blue : RGBInterface
data class Dog(val name: String, val age: Int)
Algebraic Data Type
• ProductType
interface RGBInterface
class Red : RGBInterface
class Green : RGBInterface
class Blue : RGBInterface
Algebraic Data Type
• ProductType
interface RGBInterface
class Red : RGBInterface
class Green : RGBInterface
class Blue : RGBInterface
. . .
. . .
… : RGBInterface
… : RGBInterface
Algebraic Data Type
• ProductType
data class Dog(val name: String, val age: Int)
Algebraic Data Type
• ProductType
data class Dog(val name: String, val age: Int)
Dog("A", 1)
Dog("B", 1)
Dog("B", 2)
Dog("C", 1)
Dog("C", 2)
Dog("C", 3)
. . .
. . .
Algebraic Data Type
• SumType
enum class RGB {
RED, GREEN, BLUE
}
Algebraic Data Type
• SumType
enum class RGB {
RED, GREEN, BLUE
}
RED or GREEN or BLUE
Algebraic Data Type
• SumType
sealed class Option<out T>
data class Just<T>(val value: T) : Option<T>()
object None : Option<Nothing>()
Algebraic Data Type
• SumType
sealed class Option<out T>
data class Just<T>(val value: T) : Option<T>()
object None : Option<Nothing>()
Just or None
Algebraic Data Type
• Pattern matching
Algebraic Data Type
• Pattern matching (Product Type)
val rgb: RGBInterface = Red()
val result = when (rgb) {
is Red -> "Red"
is Green -> "Green"
is Blue -> "Blue"
else -> throw IllegalArgumentException()
}
Algebraic Data Type
• Pattern matching (Product Type)
val rgb: RGBInterface = Red()
val result = when (rgb) {
is Red -> "Red"
is Green -> "Green"
is Blue -> "Blue"
else -> throw IllegalArgumentException()
}
Pink 가 추가 된다면?
Algebraic Data Type
• Pattern matching (Product Type)
interface ColorInterface
class Red : ColorInterface
class Green : ColorInterface
class Blue : ColorInterface
class Pink: ColorInterface
Algebraic Data Type
• Pattern matching (Product Type)
val rgb: ColorInterface = Pink()
val result = when (rgb) {
is Red -> "Red"
is Green -> "Green"
is Blue -> "Blue"
else -> throw IllegalArgumentException()
}
Algebraic Data Type
• Pattern matching (Product Type)
val rgb: ColorInterface = Pink()
val result = when (rgb) {
is Red -> "Red"
is Green -> "Green"
is Blue -> "Blue"
else -> throw IllegalArgumentException()
}
Compile ok
Algebraic Data Type
• Pattern matching (Product Type)
val rgb: ColorInterface = Pink()
val result = when (rgb) {
is Red -> "Red"
is Green -> "Green"
is Blue -> "Blue"
else -> throw IllegalArgumentException()
}
Runtime crash
Algebraic Data Type
• Pattern matching (Product Type)
val rgb: ColorInterface = Pink()
val result = when (rgb) {
is Red -> "Red"
is Green -> "Green"
is Blue -> "Blue"
else -> throw IllegalArgumentException()
}
Runtime crash
Algebraic Data Type
• Pattern matching (Sum Type)
Algebraic Data Type
• Pattern matching (Sum Type)
val rgb2: RGB = RGB.RED
val result2 = when (rgb2) {
RGB.RED -> "Red"
RGB.BLUE -> "Blue"
RGB.GREEN -> "Green"
}
Algebraic Data Type
• Pattern matching (Sum Type)
val rgb2: RGB = RGB.RED
val result2 = when (rgb2) {
RGB.RED -> "Red"
RGB.BLUE -> "Blue"
RGB.GREEN -> "Green"
}
ProductType가 다르게 else가 필요 없다.
Algebraic Data Type
• Pattern matching (Sum Type)
val rgb2: RGB = RGB.RED
val result2 = when (rgb2) {
RGB.RED -> "Red"
RGB.BLUE -> "Blue"
RGB.GREEN -> "Green"
}
ProductType가 다르게 else가 필요 없다.
Pink 가 추가 된다면?
Algebraic Data Type
• Pattern matching (Sum Type)
enum class COLOR {
RED, GREEN, BLUE, PINK
}
Algebraic Data Type
• Pattern matching (Sum Type)
val rgb2: Color = Color.PINK
val result2 = when (rgb2) {
Color.RED -> "Red"
Color.BLUE -> "Blue"
Color.GREEN -> "Green"
}
Compile error
Algebraic Data Type
• Pattern matching (Sum Type)
val rgb2: Color = Color.PINK
val result2 = when (rgb2) {
Color.RED -> "Red"
Color.BLUE -> "Blue"
Color.GREEN -> "Green"
}
Compile error
Algebraic Data Type
• Pattern matching (Sum Type)
val rgb2: Color = Color.PINK
val result2 = when (rgb2) {
Color.RED -> "Red"
Color.BLUE -> "Blue"
Color.GREEN -> "Green"
}
Compile error
컴파일 타임에 에러를 방지할 수 있다.
Algebraic Data Type
• Pattern matching (Sum Type)
val rgb2: Color = Color.PINK
val result2 = when (rgb2) {
Color.RED -> "Red"
Color.BLUE -> "Blue"
Color.GREEN -> "Green"
Color.PINK -> "Pink"
}
Compile ok
Exception
Exception
• none pureFunction

• partialFunction

• Maybe
Exception
• none pureFunction
Exception
• none pureFunction
fun main(args: Array<String>) {
val a = 5
val result = func(a)
println(result) // 2
}
fun func(value: Int): Int {
return 10 / value
}
Exception
• none pureFunction
fun main(args: Array<String>) {
val b = 0
val result = func(b)
println(result)
// java.lang.ArithmeticException: / by zero
}
fun func(value: Int): Int {
return 10 / value
}
Exception
• partialFunction
fun main(args: Array<String>) {
val b = 0
val result = func(b)
println(result)
// java.lang.ArithmeticException: / by zero
}
fun func(value: Int): Int {
return 10 / value
}
Exception
• partialFunction
fun func(value: Int): Int {
if(value == 0){
return -1
} else {
return 10 / value
}
}
fun func2(value: Int): Int? {
if(value == 0){
return null
} else {
return 10 / value
}
}
fun func3(value: Int): Int {
if(value == 0){
return throw ArithmeticException("")
} else {
return 10 / value
}
}
fun func4(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
Exception
• partialFunction
fun func(value: Int): Int {
if(value == 0){
return -1
} else {
return 10 / value
}
}
fun func2(value: Int): Int? {
if(value == 0){
return null
} else {
return 10 / value
}
}
fun func3(value: Int): Int {
if(value == 0){
return throw ArithmeticException("")
} else {
return 10 / value
}
}
fun func4(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
Exception
• partialFunction
fun func(value: Int): Int {
if(value == 0){
return -1
} else {
return 10 / value
}
}
fun func2(value: Int): Int? {
if(value == 0){
return null
} else {
return 10 / value
}
}
fun func3(value: Int): Int {
if(value == 0){
return throw ArithmeticException("")
} else {
return 10 / value
}
}
fun func4(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
Exception
• partialFunction
fun func(value: Int): Int {
if(value == 0){
return -1
} else {
return 10 / value
}
}
fun func2(value: Int): Int? {
if(value == 0){
return null
} else {
return 10 / value
}
}
fun func3(value: Int): Int {
if(value == 0){
return throw ArithmeticException("")
} else {
return 10 / value
}
}
fun func4(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
Exception
• partialFunction
fun func(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
fun func2(x: Int, y: Int): Int {
return x * y
}
Exception
• partialFunction
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = func2(result, b)
println(result2) // -10
}
fun func(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
fun func2(x: Int, y: Int): Int {
return x * y
}
Exception
• partialFunction
fun func(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
fun func2(x: Int, y: Int): Int {
return x * y
}
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = func2(result, b)
println(result2) // -10
}
Exception
• partialFunction
fun func(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
fun func2(x: Int, y: Int): Int {
return x * y
}
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = if (result != -1) {
func2(result, b)
} else {
-1
}
println(result2) // -1
}
Exception
• partialFunction
fun func(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
fun func2(x: Int, y: Int): Int {
return try {
x * y
} catch (e: Exception) {
-1
}
}
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = if (result != -1) {
func2(result, b)
} else {
-1
}
println(result2) // -1
}
Exception
• partialFunction

• -1을 예외상황에 사용한다면 실제값이 -1인 상황을 예외로 인식
할수 있다.

• Null 이나 exception을 사용하면 순수함수라고 할 없으며, 비즈
니스 로직의 흐름이 끊겨버린다.

• 앞의 결과를 다음 로직에 사용 하려면 항상 값 체크를 해줘야 한
다.
Exception
• Maybe
Exception
• Maybe
sealed class Maybe<out T>
data class Just<T>(val value: T) : Maybe<T>()
object None : Maybe<Nothing>()
Exception
• Maybe
sealed class Maybe<out T>
data class Just<T>(val value: T) : Maybe<T>()
object None : Maybe<Nothing>()
• 값이 있으면 Just

• 값이 없으면 None
Exception
• Maybe
fun func(value: Int): Int {
return try {
10 / value
} catch (e: Exception) {
-1
}
}
Exception
• Maybe
fun func(value: Int): Maybe<Int> {
return try {
Just(10 / value)
} catch (e: Exception) {
None
}
}
Exception
• Maybe
그래서?
Exception
• Maybe
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = if (result != -1) {
func2(result, b)
} else {
-1
}
println(result2) // -1
}
Exception
• Maybe
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = when (result) {
is Just -> func2(result.value, b)
None -> None
}
when(result2){
is Just -> println(result2.value)
None -> println("none")
}
}
Exception
• Maybe
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = when (result) {
is Just -> func2(result.value, b)
None -> None
}
when(result2){
is Just -> println(result2.value)
None -> println("none")
}
}
Exception
• Maybe
sealed class Maybe<out T>
data class Just<T>(val value: T) : Maybe<T>()
object None : Maybe<Nothing>()
Exception
• Maybe
sealed class Maybe<out T> {
abstract fun <R> map(transformer: (T) -> R): Maybe<R>
}
data class Just<T>(val value: T) : Maybe<T>() {
override fun <R> map(transformer: (T) -> R): Just<R> =
Just(transformer(value))
}
object None : Maybe<Nothing>() {
override fun <R> map(transformer: (Nothing) -> R): Maybe<R> =
None
}
Exception
• Maybe
sealed class Maybe<out T> {
abstract fun <R> map(transformer: (T) -> R): Maybe<R>
}
data class Just<T>(val value: T) : Maybe<T>() {
override fun <R> map(transformer: (T) -> R): Just<R> =
Just(transformer(value))
}
object None : Maybe<Nothing>() {
override fun <R> map(transformer: (Nothing) -> R): Maybe<R> =
None
}
Exception
• Maybe
sealed class Maybe<out T> {
abstract fun <R> map(transformer: (T) -> R): Maybe<R>
}
data class Just<T>(val value: T) : Maybe<T>() {
override fun <R> map(transformer: (T) -> R): Just<R> =
Just(transformer(value))
}
object None : Maybe<Nothing>() {
override fun <R> map(transformer: (Nothing) -> R): Maybe<R> =
None
}
Exception
• Maybe
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = if (result != -1) {
func2(result, b)
} else {
-1
}
println(result2) // -1
}
Exception
• Maybe
fun main(args: Array<String>) {
val a = 0
val result = func(a)
val b = 10
val result2 = result.map { value -> func2(value, b) }
when (result2) {
is Just -> println(result2.value)
None -> println("none")
}
}
Exception
• Maybe
val result = func(0)
val result2 = if (result != -1) {
func2(result, 10)
} else {
-1
}
val result3 = if (result2 != -1) {
func2(result2, 0)
} else {
-1
}
val result4 = if (result3 != -1) {
func2(result3, 4)
} else {
-1
}
println(result4) // -1
Exception
• Maybe
val result = func(0)
.map { func2(it, 10) }
.map { func2(it, 0) }
.map { func2(it, 4) }
println(result) // -1
실습
• IntelliJ를 실행하고 GitHub 에서 소스 다운

• https://github.com/myeonginwoo/t-academy
실습
• head 를 추가하는 addHead를 추가하자.
실습
• head 를 추가하는 addHead를 추가하자.
fun <T> FpList<T>.addHead(value: T): FpList<T> = when (this) {
Nil -> Cons(value, Nil)
is Cons -> Cons(value, this)
}
실습
• FpList<Int>의 모든 요소들의 합을 구하는 sum 함수를 일반재귀,
꼬리재귀로 만들어보자.
실습
• FpList<Int>의 모든 요소들의 합을 구하는 sum 함수를 일반재귀,
꼬리재귀로 만들어보자.
fun FpList<Int>.sum(): Int = when (this) {
Nil -> 0
is Cons -> head + tail.sum()
}
tailrec fun FpList<Int>.tailrecSum(acc: Int): Int =
when (this) {
Nil -> acc
is Cons -> tailrecSum(head + acc)
}
실습
• FpList의 요소중 앞에서부터 n개를 제외하는 drop 함수를 만들자.

• 요소의 개수가 n보다 크다면 요소의 빈리스트를

• 빈리스트면 n과 상관없이 빈리스트를 반환
실습
• FpList의 요소중 앞에서부터 n개를 제외하는 drop 함수를 만들자.

• 요소의 개수가 n보다 크다면 요소의 빈리스트를

• 빈리스트면 n과 상관없이 빈리스트를 반환
tailrec fun <T> FpList<T>.drop(n: Int): FpList<T> = when(this){
Nil -> Nil
is Cons -> when(n){
0 -> this
else -> tail.drop(n-1)
}
}
실습
• FpList의 요소중 앞에서부터 n개를 반환하는 take 함수를 만들자.

• 요소의 개수가 n보다 작다면 요소의 개수만큼 반환

• 빈리스트면 n과 상관없이 빈리스트를 반환
실습
• FpList의 요소중 앞에서부터 n개를 반환하는 take 함수를 만들자.

• 요소의 개수가 n보다 작다면 요소의 개수만큼 반환

• 빈리스트면 n과 상관없이 빈리스트를 반환
fun <T> FpList<T>.take(n: Int): FpList<T> = when (this) {
Nil -> Nil
is Cons -> when (n) {
0 -> Nil
else -> Cons(head, tail.take(n - 1))
}
}
tailrec fun <T> FpList<T>.take(n: Int, acc: FpList<T>): FpList<T> = when (this) {
Nil -> acc
is Cons -> when (n) {
0 -> acc
else -> tail.take(n - 1, acc.appendTail(head))
}
}
실습
• 타입을 변환해주는 transformer 함수를 입력받아 다른 타입의
FpList로 반환해주는 map 함수를 일반 재귀와 꼬리재귀로 만들자.
실습
• 타입을 변환해주는 transformer 함수를 입력받아 다른 타입의
FpList로 반환해주는 map 함수를 일반 재귀와 꼬리재귀로 만들자.
fun <T, R> FpList<T>.map(transformer: (T) -> R): FpList<R> =
when (this) {
Nil -> Nil
is Cons -> Cons(transformer(head), tail.map(transformer))
}
tailrec fun <T, R> FpList<T>.map(acc: FpList<R>, transformer: (T) -> R): FpList<R> =
when (this) {
Nil -> acc
is Cons -> tail.map(acc.appendTail(transformer(head)), transformer)
}
실습
• boolean을 반환하는 predicate 함수를 입력받아 요소들 중 참인
요소들만 걸러내는 filter 함수를 일반 재귀와 꼬리재귀로 만들자.
실습
• boolean을 반환하는 predicate 함수를 입력받아 요소들 중 참인
요소들만 걸러내는 filter 함수를 일반 재귀와 꼬리재귀로 만들자.
fun <T> FpList<T>.filter(predicate: (T) -> Boolean): FpList<T> =
when (this) {
Nil -> Nil
is Cons -> if (predicate(head)) {
Cons(head, tail.filter(predicate))
} else {
tail.filter(predicate)
}
}
tailrec fun <T> FpList<T>.filter(acc: FpList<T>, predicate: (T) -> Boolean): FpList<T>
when (this) {
Nil -> acc
is Cons -> if (predicate(head)) {
tail.filter(acc.appendTail(head), predicate)
} else {
tail.filter(acc, predicate)
}
}
• 사이드 이펙트를 방지 할 수 있습니다.

• 일반적으로 코드가 간결해집니다.

• 코드의 재활용성이 높아집니다.

•  게으른 평가가 가능(LazyEvaluation)

• 타입 추론이 가능
장점
• 일반적으로 코드가 간결해집니다.
장점
• 일반적으로 코드가 간결해집니다.
장점
fun unSimple(list: List<Int>): List<Int> {
val evens = mutableListOf<Int>()
for (elem in list) {
if (elem % 2 == 0) {
evens.add(elem)
}
}
val result = mutableListOf<Int>()
for (elem in evens) {
result.add(elem * 10)
}
return result
}
• 일반적으로 코드가 간결해집니다.
장점
fun simple(list: List<Int>): List<Int> = list
.filter { it % 2 == 0 }
.map { it * 10 }
• 일반적으로 코드가 간결해집니다.
장점
fun main(args: Array<String>) {
val list = listOf(1, 2, 3, 4, 5)
println(unSimple(list)) //[20, 40]
println(simple(list)) //[20, 40]
}
fun unSimple(list: List<Int>): List<Int> {
val evens = mutableListOf<Int>()
for (elem in list) {
if (elem % 2 == 0) {
evens.add(elem)
}
}
val result = mutableListOf<Int>()
for (elem in evens) {
result.add(elem * 10)
}
return result
}
fun simple(list: List<Int>): List<Int> = list
.filter { it % 2 == 0 }
.map { it * 10 }
• 높은 일반화로 코드의 재활용성이 높아집니다.
장점
• 높은 일반화로 코드의 재활용성이 높아집니다.
장점
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
• 게으른 평가가 가능(LazyEvaluation)
장점
• 게으른 평가가 가능(LazyEvaluation)
장점
• 타입 추론이 가능
장점
• 러닝커브가 높다.

• 국내 레퍼런스가 적다.

• 팀 전체가 관심있고 하려는 의지가 있어야 한다.

• 언어차원에서 지원해줘야 한다.
단점
• 러닝커브가 높다.
단점
0
25
50
75
100
시작 함수타입 고차함수 꼬리재귀 컬렉션 모나드 ...
• 러닝커브가 높다.
단점
0
25
50
75
100
시작 함수타입 고차함수 재귀 컬렉션 모나드 ...
• 국내 레퍼런스가 적다.
단점
• 국내 레퍼런스가 적다.
단점
FunFunStudy
https://github.com/funfunStudy/study/wiki
myeonginwoo@gmail.com
• 국내 레퍼런스가 적다.
단점
2019년 3월
함수형 프로그래밍
공동 저서 출간 예정!!!
• 팀 전체가 관심있고 하려는 의지가 있어야 한다.
단점
• 팀 전체가 관심있고 하려는 의지가 있어야 한다.
단점
• 언어차원에서 지원해줘야 한다.
단점
• 언어차원에서 지원해줘야 한다.
단점
Maybe<QnA>

Contenu connexe

Tendances

나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선daewon jeong
 
Python programming for Bioinformatics
Python programming for BioinformaticsPython programming for Bioinformatics
Python programming for BioinformaticsHyungyong Kim
 
Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석용 최
 
함수형 프로그래밍? 그래서 어떻게
함수형 프로그래밍? 그래서 어떻게함수형 프로그래밍? 그래서 어떻게
함수형 프로그래밍? 그래서 어떻게Gyooha Kim
 
java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰Sungchul Park
 
[새차원, 코틀린(Kotlin) 강좌] 6. Packages, Return and Jumps
[새차원, 코틀린(Kotlin) 강좌] 6. Packages, Return and Jumps[새차원, 코틀린(Kotlin) 강좌] 6. Packages, Return and Jumps
[새차원, 코틀린(Kotlin) 강좌] 6. Packages, Return and Jumps정연 최
 
Realm은 어떻게 효율적인 데이터베이스를 만들었나?
Realm은 어떻게 효율적인 데이터베이스를 만들었나?Realm은 어떻게 효율적인 데이터베이스를 만들었나?
Realm은 어떻게 효율적인 데이터베이스를 만들었나?Leonardo YongUk Kim
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개beom kyun choi
 
EcmaScript6(2015) Overview
EcmaScript6(2015) OverviewEcmaScript6(2015) Overview
EcmaScript6(2015) Overviewyongwoo Jeon
 
Javascript개발자의 눈으로 python 들여다보기
Javascript개발자의 눈으로 python 들여다보기Javascript개발자의 눈으로 python 들여다보기
Javascript개발자의 눈으로 python 들여다보기지수 윤
 
스위프트 성능 이해하기
스위프트 성능 이해하기스위프트 성능 이해하기
스위프트 성능 이해하기Yongha Yoo
 
Feel functional
Feel functionalFeel functional
Feel functionalWonJun Lee
 
알고리즘과 자료구조
알고리즘과 자료구조알고리즘과 자료구조
알고리즘과 자료구조영기 김
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개beom kyun choi
 
Swift3 generic
Swift3 genericSwift3 generic
Swift3 genericEunjoo Im
 

Tendances (20)

나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
 
Python programming for Bioinformatics
Python programming for BioinformaticsPython programming for Bioinformatics
Python programming for Bioinformatics
 
Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석
 
함수형 프로그래밍? 그래서 어떻게
함수형 프로그래밍? 그래서 어떻게함수형 프로그래밍? 그래서 어떻게
함수형 프로그래밍? 그래서 어떻게
 
java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰
 
Scala
ScalaScala
Scala
 
[새차원, 코틀린(Kotlin) 강좌] 6. Packages, Return and Jumps
[새차원, 코틀린(Kotlin) 강좌] 6. Packages, Return and Jumps[새차원, 코틀린(Kotlin) 강좌] 6. Packages, Return and Jumps
[새차원, 코틀린(Kotlin) 강좌] 6. Packages, Return and Jumps
 
Realm은 어떻게 효율적인 데이터베이스를 만들었나?
Realm은 어떻게 효율적인 데이터베이스를 만들었나?Realm은 어떻게 효율적인 데이터베이스를 만들었나?
Realm은 어떻게 효율적인 데이터베이스를 만들었나?
 
Swift의 함수와 메소드
Swift의 함수와 메소드Swift의 함수와 메소드
Swift의 함수와 메소드
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개
 
JDK 변천사
JDK 변천사JDK 변천사
JDK 변천사
 
EcmaScript6(2015) Overview
EcmaScript6(2015) OverviewEcmaScript6(2015) Overview
EcmaScript6(2015) Overview
 
Javascript개발자의 눈으로 python 들여다보기
Javascript개발자의 눈으로 python 들여다보기Javascript개발자의 눈으로 python 들여다보기
Javascript개발자의 눈으로 python 들여다보기
 
스위프트 성능 이해하기
스위프트 성능 이해하기스위프트 성능 이해하기
스위프트 성능 이해하기
 
Feel functional
Feel functionalFeel functional
Feel functional
 
알고리즘과 자료구조
알고리즘과 자료구조알고리즘과 자료구조
알고리즘과 자료구조
 
Java stream v0.1
Java stream v0.1Java stream v0.1
Java stream v0.1
 
Java8 람다
Java8 람다Java8 람다
Java8 람다
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개
 
Swift3 generic
Swift3 genericSwift3 generic
Swift3 generic
 

Similaire à Fp basic-kotlin

Cpp 0x kimRyungee
Cpp 0x kimRyungeeCpp 0x kimRyungee
Cpp 0x kimRyungeescor7910
 
11. array & pointer
11. array & pointer11. array & pointer
11. array & pointer웅식 전
 
하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문 2하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문 2Kwang Yul Seo
 
[Swift] Data Structure - Linked List
[Swift] Data Structure - Linked List[Swift] Data Structure - Linked List
[Swift] Data Structure - Linked ListBill Kim
 
Linq to object using c#
Linq to object using c#Linq to object using c#
Linq to object using c#병걸 윤
 
피보나치 수열과 파이썬.pptx
피보나치 수열과 파이썬.pptx피보나치 수열과 파이썬.pptx
피보나치 수열과 파이썬.pptxssuser791410
 
Data Structure - 1st Study
Data Structure - 1st StudyData Structure - 1st Study
Data Structure - 1st StudyChris Ohk
 
Functional programming
Functional programmingFunctional programming
Functional programmingssuserdcfefa
 
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)Kyoungchan Lee
 
Pure Function and Rx
Pure Function and RxPure Function and Rx
Pure Function and RxHyungho Ko
 
12 1. multi-dimensional array
12 1. multi-dimensional array12 1. multi-dimensional array
12 1. multi-dimensional array웅식 전
 
R 프로그래밍 기본 문법
R 프로그래밍 기본 문법R 프로그래밍 기본 문법
R 프로그래밍 기본 문법Terry Cho
 
이산수학 C1 프로젝트 3
이산수학 C1 프로젝트 3이산수학 C1 프로젝트 3
이산수학 C1 프로젝트 3pkok15
 
[Swift] Functions
[Swift] Functions[Swift] Functions
[Swift] FunctionsBill Kim
 
스칼라와 스파크 영혼의 듀오
스칼라와 스파크 영혼의 듀오스칼라와 스파크 영혼의 듀오
스칼라와 스파크 영혼의 듀오Taeoh Kim
 

Similaire à Fp basic-kotlin (20)

Cpp 0x kimRyungee
Cpp 0x kimRyungeeCpp 0x kimRyungee
Cpp 0x kimRyungee
 
11. array & pointer
11. array & pointer11. array & pointer
11. array & pointer
 
하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문 2하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문 2
 
3.포인터
3.포인터3.포인터
3.포인터
 
[Swift] Data Structure - Linked List
[Swift] Data Structure - Linked List[Swift] Data Structure - Linked List
[Swift] Data Structure - Linked List
 
Linq to object using c#
Linq to object using c#Linq to object using c#
Linq to object using c#
 
피보나치 수열과 파이썬.pptx
피보나치 수열과 파이썬.pptx피보나치 수열과 파이썬.pptx
피보나치 수열과 파이썬.pptx
 
Data Structure - 1st Study
Data Structure - 1st StudyData Structure - 1st Study
Data Structure - 1st Study
 
Functional programming
Functional programmingFunctional programming
Functional programming
 
Valentine
ValentineValentine
Valentine
 
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
 
Pure Function and Rx
Pure Function and RxPure Function and Rx
Pure Function and Rx
 
12 1. multi-dimensional array
12 1. multi-dimensional array12 1. multi-dimensional array
12 1. multi-dimensional array
 
이산수학03
이산수학03이산수학03
이산수학03
 
IPython
IPythonIPython
IPython
 
R 프로그래밍 기본 문법
R 프로그래밍 기본 문법R 프로그래밍 기본 문법
R 프로그래밍 기본 문법
 
Ch10
Ch10Ch10
Ch10
 
이산수학 C1 프로젝트 3
이산수학 C1 프로젝트 3이산수학 C1 프로젝트 3
이산수학 C1 프로젝트 3
 
[Swift] Functions
[Swift] Functions[Swift] Functions
[Swift] Functions
 
스칼라와 스파크 영혼의 듀오
스칼라와 스파크 영혼의 듀오스칼라와 스파크 영혼의 듀오
스칼라와 스파크 영혼의 듀오
 

Plus de Myeongin Woo

DroidKnight 2018 State machine by Selaed class
DroidKnight 2018 State machine by Selaed classDroidKnight 2018 State machine by Selaed class
DroidKnight 2018 State machine by Selaed classMyeongin Woo
 
Lezhin kotlin jetbrain
Lezhin kotlin jetbrainLezhin kotlin jetbrain
Lezhin kotlin jetbrainMyeongin Woo
 
Kotlin collections
Kotlin collectionsKotlin collections
Kotlin collectionsMyeongin Woo
 
토이 프로젝트를 하자.Pptx
토이 프로젝트를 하자.Pptx토이 프로젝트를 하자.Pptx
토이 프로젝트를 하자.PptxMyeongin Woo
 

Plus de Myeongin Woo (9)

Goodbye null
Goodbye nullGoodbye null
Goodbye null
 
DroidKnight 2018 State machine by Selaed class
DroidKnight 2018 State machine by Selaed classDroidKnight 2018 State machine by Selaed class
DroidKnight 2018 State machine by Selaed class
 
Lezhin kotlin jetbrain
Lezhin kotlin jetbrainLezhin kotlin jetbrain
Lezhin kotlin jetbrain
 
Kotlin collections
Kotlin collectionsKotlin collections
Kotlin collections
 
Kotlin standard
Kotlin standardKotlin standard
Kotlin standard
 
Kotlin class
Kotlin classKotlin class
Kotlin class
 
Kotlin expression
Kotlin expressionKotlin expression
Kotlin expression
 
토이 프로젝트를 하자.Pptx
토이 프로젝트를 하자.Pptx토이 프로젝트를 하자.Pptx
토이 프로젝트를 하자.Pptx
 
Kotlin.md
Kotlin.mdKotlin.md
Kotlin.md
 

Fp basic-kotlin

  • 2. FP? • Immutable DataStructure • Pure Function • Lazy evaluation
  • 4. • Immutable DataStructure FP? var mutableInt: Int = 10 mutableInt = 5 var mutableString: String = "FP" mutableString = "Kotlin"
  • 5. • Immutable DataStructure FP? var mutableInt: Int = 10 mutableInt = 5 var mutableString: String = "FP" mutableString = "Kotlin" property keyword
  • 6. • Immutable DataStructure FP? var mutableInt: Int = 10 mutableInt = 5 var mutableString: String = "FP" mutableString = "Kotlin" property name
  • 7. • Immutable DataStructure FP? var mutableInt: Int = 10 mutableInt = 5 var mutableString: String = "FP" mutableString = "Kotlin" property type
  • 8. • Immutable DataStructure FP? var mutableInt: Int = 10 mutableInt = 5 var mutableString: String = "FP" mutableString = "Kotlin" property value
  • 9. • Immutable DataStructure FP? var mutableInt: Int = 10 mutableInt = 5 var mutableString: String = "FP" mutableString = "Kotlin"
  • 10. • Immutable DataStructure FP? val immutableInt: Int = 10 immutableInt = 5 // Error val immutableString: String = "FP" immutableString = "Kotlin" // Error
  • 11. • Immutable DataStructure FP? var mutableList: MutableList<Int> = mutableListOf(1, 2, 3) mutableList.add(10)
  • 12. • Immutable DataStructure FP? var mutableList: MutableList<Int> = mutableListOf(1, 2, 3) mutableList.add(10) println(mutableList) // [1, 2, 3, 10]
  • 13. • Immutable DataStructure FP? val immutableList: List<Int> = listOf(1, 2, 3) immutableList.add(10) // Error println(immutableList) // [1, 2, 3]
  • 14. • Immutable DataStructure FP? val immutableList: List<Int> = listOf(1, 2, 3) immutableList.add(10) // Error println(immutableList) // [1, 2, 3] immutableList.plus(10)
  • 15. • Immutable DataStructure FP? val immutableList: List<Int> = listOf(1, 2, 3) immutableList.add(10) // Error println(immutableList) // [1, 2, 3] immutableList.plus(10) println(immutableList) // [1, 2, 3]
  • 16. • Immutable DataStructure FP? val immutableList: List<Int> = listOf(1, 2, 3) immutableList.add(10) // Error println(immutableList) // [1, 2, 3] immutableList.plus(10) println(immutableList) // [1, 2, 3] println(immutableList.plus(10)) // [1, 2, 3, 10]
  • 17. • Immutable DataStructure FP? val immutableList: List<Int> = listOf(1, 2, 3) immutableList.add(10) // Error println(immutableList) // [1, 2, 3] immutableList.plus(10) println(immutableList) // [1, 2, 3] println(immutableList.plus(10)) // [1, 2, 3, 10] val newList = immutableList.plus(10)
  • 18. • Immutable DataStructure FP? val immutableList: List<Int> = listOf(1, 2, 3) immutableList.add(10) // Error println(immutableList) // [1, 2, 3] immutableList.plus(10) println(immutableList) // [1, 2, 3] println(immutableList.plus(10)) // [1, 2, 3, 10] val newList = immutableList.plus(10) println(immutableList) // [1, 2, 3] println(newList) // [1, 2, 3, 10]
  • 20. • Pure Function FP? fun main(args: Array<String>) { println(pureFunction("FP")) // Hello FP } fun pureFunction(input: String): String { return "Hello " + input }
  • 21. • Pure Function FP? fun main(args: Array<String>) { println(pureFunction("FP")) // Hello FP println(pureFunction("FP")) // Hello FP println(pureFunction("FP")) // Hello FP } fun pureFunction(input: String): String { return "Hello " + input }
  • 22. • Pure Function FP? fun main(args: Array<String>) { println(nonPureFunction("FP")) // Hello FP } val strBuilder: StringBuilder = StringBuilder("Hello ") fun nonPureFunction(input: String): String { return strBuilder.append(input).toString() }
  • 23. • Pure Function FP? fun main(args: Array<String>) { println(nonPureFunction("FP")) // Hello FP } val strBuilder: StringBuilder = StringBuilder("Hello ") fun nonPureFunction(input: String): String { return strBuilder.append(input).toString() }
  • 24. • Pure Function FP? fun main(args: Array<String>) { println(nonPureFunction("FP")) // Hello FP println(nonPureFunction("FP")) // Hello FPFP println(nonPureFunction("FP")) // Hello FPFPFP } val strBuilder: StringBuilder = StringBuilder("Hello ") fun nonPureFunction(input: String): String { return strBuilder.append(input).toString() }
  • 25. • Pure Function FP? fun main(args: Array<String>) { println(nonPureFunction2(4)) // 5 } var x = 1 fun nonPureFunction2(input: Int): Int{ return input + x }
  • 26. • Pure Function FP? fun main(args: Array<String>) { println(nonPureFunction2(4)) // 5 } var x = 1 fun nonPureFunction2(input: Int): Int{ return input + x }
  • 27. • Pure Function FP? fun main(args: Array<String>) { println(nonPureFunction2(4)) // 5 println(nonPureFunction2(4)) // 5 println(nonPureFunction2(4)) // 5 } var x = 1 fun nonPureFunction2(input: Int): Int{ return input + x }
  • 28. • Pure Function FP? fun main(args: Array<String>) { println(nonPureFunction2(4)) // 5 println(nonPureFunction2(4)) // 5 println(nonPureFunction2(4)) // 5 x = 10 } var x = 1 fun nonPureFunction2(input: Int): Int{ return input + x }
  • 29. • Pure Function FP? fun main(args: Array<String>) { println(nonPureFunction2(4)) // 5 println(nonPureFunction2(4)) // 5 println(nonPureFunction2(4)) // 5 x = 10 println(nonPureFunction2(4)) // 14 } var x = 1 fun nonPureFunction2(input: Int): Int{ return input + x }
  • 31. • Lazy evaluation FP? val lazyValue: String by lazy { println("시간이 오래 걸리는 작업") "hello" } fun main(args: Array<String>) { println(lazyValue) println(lazyValue) }
  • 32. • Lazy evaluation FP? val lazyValue: String by lazy { println("시간이 오래 걸리는 작업") "hello" } fun main(args: Array<String>) { println(lazyValue) println(lazyValue) } 시간이 오래 걸리는 작업 hello hello
  • 33. • Lazy evaluation FP? val lazyValue: String by lazy { println("시간이 오래 걸리는 작업") "hello" } fun main(args: Array<String>) { println(lazyValue) println(lazyValue) } 시간이 오래 걸리는 작업 hello hello
  • 34. • Lazy evaluation FP? val infiniteValue = generateSequence(0) { it + 1 } infiniteValue .take(5) .forEach { print("$it ") }
  • 35. • Lazy evaluation FP? val infiniteValue = generateSequence(0) { it + 1 } infiniteValue .take(5) .forEach { print("$it ") } //0 1 2 3 4
  • 36. • Lazy evaluation FP? val lazyValue2: () -> Unit = { println("FP") } lazyValue2 lazyValue2 lazyValue2 lazyValue2()
  • 37. • Lazy evaluation FP? val lazyValue2: () -> Unit = { println("FP") } lazyValue2 // lazyValue2 // lazyValue2 // lazyValue2() // FP
  • 39. Functional Data Structure • control with pure functions • Immutable Data Structure • Data Share
  • 40. Functional Data Structure fun main(args: Array<String>) { val value = 3 val result = plusThree(value) } fun plusThree(x: Int): Int { return x + 3 }
  • 41. Functional Data Structure fun main(args: Array<String>) { val value = 3 val result = plusThree(value) println(result) // 6 println(value) // 3 } fun plusThree(x: Int): Int { return x + 3 }
  • 42. Functional Data Structure fun main(args: Array<String>) { val list = listOf(1, 2) val listResult = plusThree(list) } fun plusThree(list: List<Int>): List<Int> { return list.plus(3) }
  • 43. Functional Data Structure fun main(args: Array<String>) { val list = listOf(1, 2) val listResult = plusThree(list) println(list) // [1, 2] println(listResult) // [1, 2, 3] } fun plusThree(list: List<Int>): List<Int> { return list.plus(3) }
  • 45. Functional Data Structure • Data Share val list = listOf(1, 2)
  • 46. Functional Data Structure • Data Share val list = listOf(1, 2) 1 2 Cons Cons Head Tail Head Tail NIL list
  • 47. Functional Data Structure • Data Share val list = listOf(1, 2) val listResult = plusThree(list) 1 2 Cons Cons Head Tail Head Tail list NIL
  • 48. Functional Data Structure • Data Share fun plusThree(list: List<Int>): List<Int> { return list.plus(3) } Tail NIL1 2 Head Tail Head Tail NIL list
  • 49. Functional Data Structure • Data Share list fun plusThree(list: List<Int>): List<Int> { return list.plus(3) } Tail 3 Cons Head Tail NIL1 2 Head Tail Head Tail 1 2 Head Tail Head Tail NIL list • Data Share
  • 50. Functional Data Structure • Data Share 1 2 Cons Cons Head Tail Head Tail 3 Cons Head Tail NIL val listResult = plusThree(list) listResult
  • 51. Functional Data Structure val tail = listResult.tail() • Data Share
  • 52. Functional Data Structure val tail = listResult.tail() • Data Share 1 2 Cons Cons Head Tail Head Tail listResult 3 Cons Head Tail NIL Tail
  • 53. Functional Data Structure val tail = listResult.tail() • Data Share 2 Cons Head Tail 3 Cons Head Tail NIL Tail
  • 55. Recursion • solutions to smaller instances of the same problem
  • 56. Recursion • solutions to smaller instances of the same problem
  • 57. Recursion • Tip • 어떻게 보다 무엇에 집중. • 종료조건부터 생각하자. • 재귀를 반복 할수록 종료 조건으로 수렴.
  • 58. Recursion fun factorial(num: Int): Int { var result = 1 for (i in 1..num) { result *= i } return result }
  • 59. Recursion fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) }
  • 60. Recursion fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) } Readability +
  • 61. Recursion n * factorial2( n-1) fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) }
  • 62. Recursion n * factorial2( n-1) n * (n-1 * factorial2(n -2) ) fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) }
  • 63. Recursion n * factorial2( n-1) n * (n-1 * factorial2(n -2) ) n * (n-2 * (n-3 * factorial2(n-3))) n * (n-2 * (n-3 * (n-4 * factorial2(n-4)))) ….. ((((((1)))))) fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) }
  • 64. Recursion fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) } n * factorial2( n-1) n * (n-1 * factorial2(n -2) ) n * (n-2 * (n-3 * factorial2(n-3))) n * (n-2 * (n-3 * (n-4 * factorial2(n-4)))) ….. ((((((1)))))) n * (n-2 * (n-3 * (n-4 * 1))) n * (n-2 * (n-3 * n-4 * 1)) n * (n-2 * n-3 * n-4 * 1) n * n-2 * n-3 * n-4 * 1
  • 65. Recursion 5 * factorial2(4) 5 * (4 * factorial2(3)) 5 * (4 * (3 * factorial2(2))) 5 * (4 * (3 * (2 * factorial2(1)))) 5 * (4 * (3 * (2 * (1)))) 5 * (4 * (3 * (2))) 5 * (4 * (6)) 5 * (24) 120 fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) }
  • 66. Recursion 5 * factorial2(4) 5 * (4 * factorial2(3)) 5 * (4 * (3 * factorial2(2))) 5 * (4 * (3 * (2 * factorial2(1)))) 5 * (4 * (3 * (2 * (1)))) 5 * (4 * (3 * (2))) 5 * (4 * (6)) 5 * (24) 120 Performance - fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) }
  • 67. Recursion 5 * factorial2(4) 5 * (4 * factorial2(3)) 5 * (4 * (3 * factorial2(2))) 5 * (4 * (3 * (2 * factorial2(1)))) 5 * (4 * (3 * (2 * (1)))) 5 * (4 * (3 * (2))) 5 * (4 * (6)) 5 * (24) 120 Performance - SOF fun factorial2(num: Int): Int = when (num) { 1 -> 1 else -> num * factorial2(num - 1) }
  • 68. Recursion • Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀 로 구현하자
  • 69. Recursion • Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀 로 구현하자 종료조건?
  • 70. Recursion • Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀 로 구현하자 fun getMaxValue(list: List<Int>): Int = when { list.isEmpty() -> throw NullPointerException() list.size == 1 -> list.first() } 종료조건?
  • 71. Recursion • Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀 로 구현하자 fun getMaxValue(list: List<Int>): Int = when { list.isEmpty() -> throw NullPointerException() list.size == 1 -> list.first() } 종료 조건으로 수렴?
  • 72. Recursion • Int 리스트 값중 최대값을 구하는 함수 getMaxValue 함수를 재귀 로 구현하자 fun getMaxValue(list: List<Int>): Int = when { list.isEmpty() -> throw NullPointerException() list.size == 1 -> list.first() else -> if (list.first() > getMaxValue(list.drop(1))) { list.first() } else { getMaxValue(list.drop(1)) } } 종료 조건으로 수렴?
  • 73. Recursion tailrec fun factorial3(num: Int, acc: Int = 1): Int = when (num) { 1 -> acc else -> factorial3(num - 1, acc * num) }
  • 74. Recursion tailrec fun factorial3(num: Int, acc: Int = 1): Int = when (num) { 1 -> acc else -> factorial3(num - 1, acc * num) }
  • 75. • TailRecursion Recursion tailrec fun factorial3(num: Int, acc: Int = 1): Int = when (num) { 1 -> acc else -> factorial3(num - 1, acc * num) } factorial3( n-1, n)
  • 76. • TailRecursion Recursion tailrec fun factorial3(num: Int, acc: Int = 1): Int = when (num) { 1 -> acc else -> factorial3(num - 1, acc * num) } factorial3( n-1, n) factorial3( n-2, acc * n-1) factorial3( n-3, acc * n-2)
  • 77. • TailRecursion Recursion tailrec fun factorial3(num: Int, acc: Int = 1): Int = when (num) { 1 -> acc else -> factorial3(num - 1, acc * num) } factorial3( n-1, n) factorial3( n-2, acc * n-1) factorial3( n-3, acc * n-2) … factorial3( 1, acc ….) acc
  • 78. • TailRecursion Recursion tailrec fun factorial3(num: Int, acc: Int = 1): Int = when (num) { 1 -> acc else -> factorial3(num - 1, acc * num) } Readability +
  • 79. • TailRecursion Recursion tailrec fun factorial3(num: Int, acc: Int = 1): Int = when (num) { 1 -> acc else -> factorial3(num - 1, acc * num) } Readability + Performance +
  • 80. • TailRecursion Recursion tailrec fun factorial3(num: Int, acc: Int = 1): Int = when (num) { 1 -> acc else -> factorial3(num - 1, acc * num) } Readability + Performance + !SOP
  • 81. Recursion • 연습문제 (exercise1) • getMaxValue를 꼬리 재귀로 만들어보자.
  • 82. Recursion • 연습문제 (exercise1) • getMaxValue를 꼬리 재귀로 만들어보자. tailrec fun getMaxValue(list: List<Int>, acc: Int): Int = when { list.isEmpty() -> throw NullPointerException() list.size == 1 -> acc else -> if (list.first() >= acc) { getMaxValue(list.drop(1), list.first()) } else { getMaxValue(list.drop(1), acc) } }
  • 83. Recursion • 연습문제 (exercise1) • getMaxValue를 꼬리 재귀로 만들어보자. tailrec fun getMaxValue(list: List<Int>, acc: Int): Int = when { list.isEmpty() -> throw NullPointerException() list.size == 1 -> acc else -> if (list.first() >= acc) { getMaxValue(list.drop(1), list.first()) } else { getMaxValue(list.drop(1), acc) } } 종료조건
  • 84. Recursion • 연습문제 (exercise1) • getMaxValue를 꼬리 재귀로 만들어보자. tailrec fun getMaxValue(list: List<Int>, acc: Int): Int = when { list.isEmpty() -> throw NullPointerException() list.size == 1 -> acc else -> if (list.first() >= acc) { getMaxValue(list.drop(1), list.first()) } else { getMaxValue(list.drop(1), acc) } } 종료조건으로 수렴하는 로직
  • 88. Function Type val functionType: () -> Unit Input Output
  • 89. Function Type val functionType: () -> Unit val functionType1: (Int) -> Unit val functionType2: (Int, String) -> Unit
  • 90. Function Type val functionType: () -> Unit val functionType1: (Int) -> Unit val functionType2: (Int, String) -> Unit functionType = { println("FP") } functionType1 = { value -> println(value.toString()) } functionType2 = { intValue, stringValie -> println("intValue $intValue, stringValue $stringValie") }
  • 91. Function Type val functionType: () -> Unit val functionType1: (Int) -> Unit val functionType2: (Int, String) -> Unit functionType = { println("FP") } functionType1 = { value -> println(value.toString()) } functionType2 = { intValue, stringValie -> println("intValue $intValue, stringValue $stringValie") } functionType() // FP functionType1(10) // 10 functionType2(10, "FP") // intValue 10, stringVAlue FP
  • 92. • 연습문제 2: • Int 타입 2개를 입력받아서, 입력받은 두 값을 곱한 결과 값 을 반환하는 함수타입 프로퍼티 product를 만들어 보자. Function Type
  • 93. • 연습문제 2: • Int 타입 2개를 입력받아서, 입력받은 두 값을 곱한 결과 값 을 반환하는 함수타입 프로퍼티 product를 만들어 보자. • 연습문제 2: • String 타입 3개를 입력받아서, 하나의 스트링으로 합쳐주는 함 수타입 프로퍼티 appendStrings 를 만들어보자. Function Type
  • 95. • Pass a function as an Argument • Return a function • Assign a function to a data structure First Class Citizen
  • 96. • Pass a function as an Argument First Class Citizen fun function(param: () -> Unit) { // something }
  • 97. • Return a function First Class Citizen fun function2(): () -> Unit { return { println("FP") } }
  • 98. • Assign a function to a data structure First Class Citizen val value1: () -> Unit = { println("FP") }
  • 99. • Assign a function to a data structure First Class Citizen val value1: () -> Unit = { println("FP") } val value2: List<() -> Unit> = listOf({ println("FP") })
  • 100. • Assign a function to a data structure First Class Citizen val value1: () -> Unit = { println("FP") } val value2: List<() -> Unit> = listOf({ println("FP") }) val value3: Map<String, () -> Unit> = mapOf("FP" to { println("FP") })
  • 102. Higher-order function • Pass a function as an Argument • Return a function • Pass a function as an Argument OR Return a function
  • 103. Higher-order function • Pass a function as an Argument
  • 104. Higher-order function • Pass a function as an Argument fun higherOrderFunction1(func: () -> Unit) { func() }
  • 105. Higher-order function • Pass a function as an Argument fun higherOrderFunction1(func: () -> Unit) { func() }
  • 107. Higher-order function • Return a function fun higherOrderFunction2(): () -> Unit { return { println("FP") } }
  • 108. Higher-order function • Return a function fun higherOrderFunction2(): () -> Unit { return { println("FP") } }
  • 109. Higher-order function • Pass a function as an Argument OR Return a function
  • 110. Higher-order function • Pass a function as an Argument OR Return a function fun higherOrderFunction1(func: () -> Unit) { func() } fun higherOrderFunction2(): () -> Unit { return { println("FP") } } fun higherOrderFunction3(func: () -> Unit): () -> Unit { return func }
  • 112. CallByName fun callByName(): () -> String = { println("callByName") // shomething "callByName" }
  • 113. CallByName fun callByName(): () -> String = { println("callByName") // shomething "callByName" } fun callByValue(): String { println("callByValue") return "callByValue" }
  • 114. CallByName fun main(args: Array<String>) { callByName() // "" callByValue() // "callByValue" } fun callByName(): () -> String = { println("callByName") // shomething "callByName" } fun callByValue(): String { println("callByValue") return "callByValue" }
  • 115. CallByName fun main(args: Array<String>) { callByName() // "" callByValue() // "callByValue" } fun callByName(): () -> String = { println("callByName") // shomething "callByName" } fun callByValue(): String { println("callByValue") return "callByValue" }
  • 116. CallByName fun main(args: Array<String>) { callByName() // "" callByValue() // "callByValue" } fun callByName(): () -> String = { println("callByName") // shomething "callByName" } fun callByValue(): String { println("callByValue") return "callByValue" }
  • 117. CallByName fun main(args: Array<String>) { callByName()() // "callByName" callByValue() // "callByValue" } fun callByName(): () -> String = { println("callByName") // shomething "callByName" } fun callByValue(): String { println("callByValue") return "callByValue" }
  • 119. CallByName fun doCallByName(condtion: Boolean, callByName: () -> String) { if (condtion) { callByName() } } fun doCallByValue(condtion: Boolean, callByValue: String) { if (condtion) { callByValue } }
  • 120. CallByName fun doCallByName(condtion: Boolean, callByName: () -> String) { if (condtion) { callByName() } } fun doCallByValue(condtion: Boolean, callByValue: String) { if (condtion) { callByValue } }
  • 121. CallByName fun doCallByName(condtion: Boolean, callByName: () -> String) { if (condtion) { callByName() } } fun doCallByValue(condtion: Boolean, callByValue: String) { if (condtion) { callByValue } }
  • 122. CallByName fun doCallByValue(condtion: Boolean, callByValue: String) { if (condtion) { callByValue } } fun callByValue(): String { println("callByValue") return "FP" } doCallByValue(true, callByValue()) // "callByValue"
  • 123. CallByName fun doCallByValue(condtion: Boolean, callByValue: String) { if (condtion) { callByValue } } fun callByValue(): String { println("callByValue") return "FP" } doCallByValue(true, callByValue()) // "callByValue" doCallByValue(false, callByValue()) // "callByValue"
  • 124. CallByName fun doCallByName(condtion: Boolean, callByName: () -> String) { if (condtion) { callByName() } } fun callByName(): () -> String = { println("callByName") // shomething "FP" } doCallByName(true, callByName()) // "callByName"
  • 125. CallByName fun doCallByName(condtion: Boolean, callByName: () -> String) { if (condtion) { callByName() } } fun callByName(): () -> String = { println("callByName") // shomething "FP" } doCallByName(true, callByName()) // "callByName" doCallByName(false, callByName()) // ""
  • 126. CallByName • 함수의 값을 전달하지 않고 함수의 이름을 전달 할수 있다.
  • 127. CallByName • 함수의 값을 전달하지 않고 함수의 이름을 전달 할수 있다. • 함수의 이름을 전달하면, 전달하는 시점에 함수가 실행되지 않는다.
  • 128. CallByName • 함수의 값을 전달하지 않고 함수의 이름을 전달 할수 있다. • 함수의 이름을 전달하면, 전달하는 시점에 함수가 실행되지 않는다. • 특정 상황에 따라 크고 무거운 연산을 하거나 하지 않을 경우 이름 에 의한 호출을 하면 훨씬 효율적이다.
  • 129. CallByName • 함수의 값을 전달하지 않고 함수의 이름을 전달 할수 있다. • 함수의 이름을 전달하면, 전달하는 시점에 함수가 실행되지 않는다. • 특정 상황에 따라 크고 무거운 연산을 하거나 하지 않을 경우 이름 에 의한 호출을 하면 훨씬 효율적이다. 게으른 연산(Lazy Evaluation)
  • 131. Partial Applied Function • Partial Applied Function • Curring
  • 132. Partial Applied Function • Partial Applied Function val func: (Int, Int) -> Int = { x, y -> x + y } println(func(5, 10)) // 15
  • 133. Partial Applied Function • Partial Applied Function val func: (Int, Int) -> Int = { x, y -> x + y } println(func(5, 10)) // 15 x 값은 알고있지만 y는 나중에 알수 있다면??
  • 134. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y는 나중에 알수 있다면?? fun <P1, P2, R> ((P1, P2) -> R).partialAppliedFunction(x: P1): (P2) -> R { return { p2 -> this(x, p2) } }
  • 135. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y는 나중에 알수 있다면?? fun <P1, P2, R> ((P1, P2) -> R).partialAppliedFunction(x: P1): (P2) -> R { return { p2 -> this(x, p2) } }
  • 136. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y는 나중에 알수 있다면?? fun <P1, P2, R> ((P1, P2) -> R).partialAppliedFunction(x: P1): (P2) -> R { return { p2 -> this(x, p2) } }
  • 137. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y는 나중에 알수 있다면?? fun <P1, P2, R> ((P1, P2) -> R).partialAppliedFunction(x: P1): (P2) -> R { return { p2 -> this(x, p2) } }
  • 138. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y는 나중에 알수 있다면?? val partial = func.partialAppliedFunction(5) // doSomething
  • 139. Partial Applied Function • Partial Applied Function val partial = func.partialAppliedFunction(5) // doSomething println(partial(10)) // 15
  • 140. Partial Applied Function • Partial Applied Function val multiThree = { x: Int, y: Int, z: Int -> x * y * z } println(multiThree(1, 2, 3)) // 6
  • 141. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y, z 는 나중에 알수 있다면?? val multiThree = { x: Int, y: Int, z: Int -> x * y * z } println(multiThree(1, 2, 3)) // 6
  • 142. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y, z 는 나중에 알수 있다면?? fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R { return { p2, P3 -> this(x, p2, P3) } }
  • 143. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y, z 는 나중에 알수 있다면?? fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R { return { p2, P3 -> this(x, p2, P3) } }
  • 144. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y, z 는 나중에 알수 있다면?? fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R { return { p2, P3 -> this(x, p2, P3) } }
  • 145. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y, z 는 나중에 알수 있다면?? fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R { return { p2, P3 -> this(x, p2, P3) } }
  • 146. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y, z 는 나중에 알수 있다면?? fun <P1, P2, P3, R> ((P1, P2, P3) -> R).partialAppliedFunction(x: P1): (P2, P3) -> R { return { p2, P3 -> this(x, p2, P3) } }
  • 147. Partial Applied Function • Partial Applied Function x 값은 알고있지만 y, z 는 나중에 알수 있다면?? val partial2 = multiThree.partialAppliedFunction(1) println(partial2(2, 3)) // 6
  • 148. • 연습문제 3: • 입력값 4개를 중 2개를 먼저 입력받고 나머지 2개는 나중에 받 는 (P1, P2, P3, P4) -> R의 확장함수 면서 부분 함수인 partialAppliedFunction을 만들자. • Int값 4개를 입력받아서 모든 값을 더한 결과를 반환하는 함수타 입 프로퍼티 sumFour 를 만들자. • sumFor에 partialAppliedFunction을 적용해보자. Partial Applied Function
  • 150. Partial Applied Function • Curring val multiThree = { x: Int, y: Int, z: Int -> x * y * z } println(multiThree(1, 2, 3)) // 6 x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
  • 151. Partial Applied Function • Curring fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R = { p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } } x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
  • 152. Partial Applied Function • Curring fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R = { p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } } val curriedMultiThree = multiThree.curried() println(curriedMultiThree(1)(2)(3)) // 6 x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
  • 153. Partial Applied Function • Curring fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R = { p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } } val curriedMultiThree = multiThree.curried() println(curriedMultiThree(1)(2)(3)) // 6 val p1 = curriedMultiThree(1) // doSomething x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
  • 154. Partial Applied Function • Curring fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R = { p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } } val curriedMultiThree = multiThree.curried() println(curriedMultiThree(1)(2)(3)) // 6 val p1 = curriedMultiThree(1) // doSomething val p2 = p1(2) // doSomething x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
  • 155. Partial Applied Function • Curring fun <P1, P2, P3, R> ((P1, P2, P3) -> R).curried(): (P1) -> (P2) -> (P3) -> R = { p1: P1 -> { p2: P2 -> { p3: P3 -> this(p1, p2, p3) } } } val curriedMultiThree = multiThree.curried() println(curriedMultiThree(1)(2)(3)) // 6 val p1 = curriedMultiThree(1) // doSomething val p2 = p1(2) // doSomething val p3 = p2(3) // doSomething println(p3) //6 x 값은 컴파일 타임에 알고 있지만 y, z값은 런타임에 각각 전달받는다면?
  • 157. Collection(Stream) • map • filter • drop • dropWhile • take • groupBy • fold, foldRight
  • 158. Collection(Stream) • map public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> { return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform) }
  • 159. Collection(Stream) • map val list = listOf(1, 2, 3, 4, 5, 6)
  • 160. Collection(Stream) • map val list = listOf(1, 2, 3, 4, 5, 6) println(list.map { value -> value * value }) // [1, 4, 9, 16, 25, 36]
  • 161. Collection(Stream) • filter public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> { return filterTo(ArrayList<T>(), predicate) }
  • 162. Collection(Stream) • filter val list = listOf(1, 2, 3, 4, 5, 6)
  • 163. Collection(Stream) • filter val list = listOf(1, 2, 3, 4, 5, 6) println(list.filter { value -> value % 2 == 0 }) // [2, 4, 6]
  • 164. Collection(Stream) • drop public fun <T> Iterable<T>.drop(n: Int): List<T> { require(n >= 0) { "Requested element count $n is less than zero." } if (n == 0) return toList() val list: ArrayList<T> if (this is Collection<*>) { val resultSize = size - n if (resultSize <= 0) return emptyList() if (resultSize == 1) return listOf(last()) list = ArrayList<T>(resultSize) if (this is List<T>) { if (this is RandomAccess) { for (index in n until size) list.add(this[index]) } else { for (item in listIterator(n)) list.add(item) } return list } } else { list = ArrayList<T>() } var count = 0 for (item in this) { if (count++ >= n) list.add(item) } return list.optimizeReadOnlyList() }
  • 165. Collection(Stream) • drop val list = listOf(1, 2, 3, 4, 5, 6)
  • 166. Collection(Stream) • drop val list = listOf(1, 2, 3, 4, 5, 6) println(list.drop(1)) // [2, 3, 4, 5, 6]
  • 167. Collection(Stream) • dropWhile public inline fun <T> Iterable<T>.dropWhile(predicate: (T) -> Boolean): List<T> { var yielding = false val list = ArrayList<T>() for (item in this) if (yielding) list.add(item) else if (!predicate(item)) { list.add(item) yielding = true } return list }
  • 168. Collection(Stream) • dropWhile val list = listOf(1, 2, 3, 4, 5, 6)
  • 169. Collection(Stream) • dropWhile val list = listOf(1, 2, 3, 4, 5, 6) println(list.dropWhile { value -> value < 3 }) // [3, 4, 5, 6]
  • 171. Collection(Stream) • filter vs dropWhile val list = listOf(1, 2, 3, 4, 5, 6) println(list.filter { value -> value % 2 == 1 }) println(list.dropWhile { value -> value % 2 == 1 })
  • 172. Collection(Stream) • filter vs dropWhile val list = listOf(1, 2, 3, 4, 5, 6) println(list.filter { value -> value % 2 == 1 }) // [1, 3, 5] println(list.dropWhile { value -> value % 2 == 1 }) // [2, 3, 4, 5, 6]
  • 173. Collection(Stream) • take public fun <T> Iterable<T>.take(n: Int): List<T> { require(n >= 0) { "Requested element count $n is less than zero." } if (n == 0) return emptyList() if (this is Collection<T>) { if (n >= size) return toList() if (n == 1) return listOf(first()) } var count = 0 val list = ArrayList<T>(n) for (item in this) { if (count++ == n) break list.add(item) } return list.optimizeReadOnlyList() }
  • 174. Collection(Stream) • take val list = listOf(1, 2, 3, 4, 5, 6)
  • 175. Collection(Stream) • take val list = listOf(1, 2, 3, 4, 5, 6) println(list.take(3)) // [1, 2, 3]
  • 176. Collection(Stream) • groupBy public inline fun <T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> { return groupByTo(LinkedHashMap<K, MutableList<T>>(), keySelector) }
  • 177. Collection(Stream) • groupBy val list = listOf(1, 2, 3, 4, 5, 6)
  • 178. Collection(Stream) • groupBy val list = listOf(1, 2, 3, 4, 5, 6) println(list.groupBy { value -> value % 2 }) // {1=[1, 3, 5], 0=[2, 4, 6]}
  • 179. Collection(Stream) • fold public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R { var accumulator = initial for (element in this) accumulator = operation(accumulator, element) return accumulator }
  • 180. Collection(Stream) • fold val list = listOf(1, 2, 3, 4, 5, 6)
  • 181. Collection(Stream) • fold val list = listOf(1, 2, 3, 4, 5, 6) println(list.fold(0) { acc, value -> acc + value }) // 21
  • 182. Collection(Stream) • foldRight public inline fun <T, R> List<T>.foldRight(initial: R, operation: (T, acc: R) -> R): R { var accumulator = initial if (!isEmpty()) { val iterator = listIterator(size) while (iterator.hasPrevious()) { accumulator = operation(iterator.previous(), accumulator) } } return accumulator }
  • 183. Collection(Stream) • foldRight val list = listOf(1, 2, 3, 4, 5, 6)
  • 184. Collection(Stream) • foldRight val list = listOf(1, 2, 3, 4, 5, 6) println(list.foldRight(0) { value, acc -> acc + value }) // 21
  • 185. Collection(Stream) • foldLeft vs foldRight list1 = listOf("a", "b", "c", "d", "e", "f") println(list1.foldRight("") { value, acc -> acc + value }) println(list1.fold("") { acc, value -> acc + value })
  • 186. Collection(Stream) • foldLeft vs foldRight list1 = listOf("a", "b", "c", "d", "e", "f") println(list1.foldRight("") { value, acc -> acc + value }) println(list1.fold("") { acc, value -> acc + value }) // abcdef
  • 187. Collection(Stream) • foldLeft vs foldRight list1 = listOf("a", "b", "c", "d", "e", "f") println(list1.foldRight("") { value, acc -> acc + value }) // fedcba println(list1.fold("") { acc, value -> acc + value }) // abcdef
  • 188. 연습문제 • exercise4 파일에 있는 list와 collection api를 사용해서 새로운 list를 만들자. • 나이가 30 이상이고, single 인 사람들의 이름을 반환
  • 189. 연습문제 • exercise4 파일에 있는 list와 collection api를 사용해서 새로운 list를 만들자. • 나이가 30 이상이고, single 인 사람들의 이름을 반환 list.filter { person -> person.age > 30 } .filter { person -> person.single } .map { person -> person.name }
  • 191. Algebraic Data Type • ProductType / SumType • Pattern Matching
  • 192. Algebraic Data Type interface RGBInterface class Red : RGBInterface class Green : RGBInterface class Blue : RGBInterface data class Dog(val name: String, val age: Int) enum class RGB { RED, GREEN, BLUE } sealed class Option<out T> data class Just<T>(val value: T) : Option<T>() object None : Option<Nothing>()
  • 193. Algebraic Data Type • ProductType interface RGBInterface class Red : RGBInterface class Green : RGBInterface class Blue : RGBInterface data class Dog(val name: String, val age: Int)
  • 194. Algebraic Data Type • ProductType interface RGBInterface class Red : RGBInterface class Green : RGBInterface class Blue : RGBInterface
  • 195. Algebraic Data Type • ProductType interface RGBInterface class Red : RGBInterface class Green : RGBInterface class Blue : RGBInterface . . . . . . … : RGBInterface … : RGBInterface
  • 196. Algebraic Data Type • ProductType data class Dog(val name: String, val age: Int)
  • 197. Algebraic Data Type • ProductType data class Dog(val name: String, val age: Int) Dog("A", 1) Dog("B", 1) Dog("B", 2) Dog("C", 1) Dog("C", 2) Dog("C", 3) . . . . . .
  • 198. Algebraic Data Type • SumType enum class RGB { RED, GREEN, BLUE }
  • 199. Algebraic Data Type • SumType enum class RGB { RED, GREEN, BLUE } RED or GREEN or BLUE
  • 200. Algebraic Data Type • SumType sealed class Option<out T> data class Just<T>(val value: T) : Option<T>() object None : Option<Nothing>()
  • 201. Algebraic Data Type • SumType sealed class Option<out T> data class Just<T>(val value: T) : Option<T>() object None : Option<Nothing>() Just or None
  • 202. Algebraic Data Type • Pattern matching
  • 203. Algebraic Data Type • Pattern matching (Product Type) val rgb: RGBInterface = Red() val result = when (rgb) { is Red -> "Red" is Green -> "Green" is Blue -> "Blue" else -> throw IllegalArgumentException() }
  • 204. Algebraic Data Type • Pattern matching (Product Type) val rgb: RGBInterface = Red() val result = when (rgb) { is Red -> "Red" is Green -> "Green" is Blue -> "Blue" else -> throw IllegalArgumentException() } Pink 가 추가 된다면?
  • 205. Algebraic Data Type • Pattern matching (Product Type) interface ColorInterface class Red : ColorInterface class Green : ColorInterface class Blue : ColorInterface class Pink: ColorInterface
  • 206. Algebraic Data Type • Pattern matching (Product Type) val rgb: ColorInterface = Pink() val result = when (rgb) { is Red -> "Red" is Green -> "Green" is Blue -> "Blue" else -> throw IllegalArgumentException() }
  • 207. Algebraic Data Type • Pattern matching (Product Type) val rgb: ColorInterface = Pink() val result = when (rgb) { is Red -> "Red" is Green -> "Green" is Blue -> "Blue" else -> throw IllegalArgumentException() } Compile ok
  • 208. Algebraic Data Type • Pattern matching (Product Type) val rgb: ColorInterface = Pink() val result = when (rgb) { is Red -> "Red" is Green -> "Green" is Blue -> "Blue" else -> throw IllegalArgumentException() } Runtime crash
  • 209. Algebraic Data Type • Pattern matching (Product Type) val rgb: ColorInterface = Pink() val result = when (rgb) { is Red -> "Red" is Green -> "Green" is Blue -> "Blue" else -> throw IllegalArgumentException() } Runtime crash
  • 210. Algebraic Data Type • Pattern matching (Sum Type)
  • 211. Algebraic Data Type • Pattern matching (Sum Type) val rgb2: RGB = RGB.RED val result2 = when (rgb2) { RGB.RED -> "Red" RGB.BLUE -> "Blue" RGB.GREEN -> "Green" }
  • 212. Algebraic Data Type • Pattern matching (Sum Type) val rgb2: RGB = RGB.RED val result2 = when (rgb2) { RGB.RED -> "Red" RGB.BLUE -> "Blue" RGB.GREEN -> "Green" } ProductType가 다르게 else가 필요 없다.
  • 213. Algebraic Data Type • Pattern matching (Sum Type) val rgb2: RGB = RGB.RED val result2 = when (rgb2) { RGB.RED -> "Red" RGB.BLUE -> "Blue" RGB.GREEN -> "Green" } ProductType가 다르게 else가 필요 없다. Pink 가 추가 된다면?
  • 214. Algebraic Data Type • Pattern matching (Sum Type) enum class COLOR { RED, GREEN, BLUE, PINK }
  • 215. Algebraic Data Type • Pattern matching (Sum Type) val rgb2: Color = Color.PINK val result2 = when (rgb2) { Color.RED -> "Red" Color.BLUE -> "Blue" Color.GREEN -> "Green" } Compile error
  • 216. Algebraic Data Type • Pattern matching (Sum Type) val rgb2: Color = Color.PINK val result2 = when (rgb2) { Color.RED -> "Red" Color.BLUE -> "Blue" Color.GREEN -> "Green" } Compile error
  • 217. Algebraic Data Type • Pattern matching (Sum Type) val rgb2: Color = Color.PINK val result2 = when (rgb2) { Color.RED -> "Red" Color.BLUE -> "Blue" Color.GREEN -> "Green" } Compile error 컴파일 타임에 에러를 방지할 수 있다.
  • 218. Algebraic Data Type • Pattern matching (Sum Type) val rgb2: Color = Color.PINK val result2 = when (rgb2) { Color.RED -> "Red" Color.BLUE -> "Blue" Color.GREEN -> "Green" Color.PINK -> "Pink" } Compile ok
  • 220. Exception • none pureFunction • partialFunction • Maybe
  • 222. Exception • none pureFunction fun main(args: Array<String>) { val a = 5 val result = func(a) println(result) // 2 } fun func(value: Int): Int { return 10 / value }
  • 223. Exception • none pureFunction fun main(args: Array<String>) { val b = 0 val result = func(b) println(result) // java.lang.ArithmeticException: / by zero } fun func(value: Int): Int { return 10 / value }
  • 224. Exception • partialFunction fun main(args: Array<String>) { val b = 0 val result = func(b) println(result) // java.lang.ArithmeticException: / by zero } fun func(value: Int): Int { return 10 / value }
  • 225. Exception • partialFunction fun func(value: Int): Int { if(value == 0){ return -1 } else { return 10 / value } } fun func2(value: Int): Int? { if(value == 0){ return null } else { return 10 / value } } fun func3(value: Int): Int { if(value == 0){ return throw ArithmeticException("") } else { return 10 / value } } fun func4(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } }
  • 226. Exception • partialFunction fun func(value: Int): Int { if(value == 0){ return -1 } else { return 10 / value } } fun func2(value: Int): Int? { if(value == 0){ return null } else { return 10 / value } } fun func3(value: Int): Int { if(value == 0){ return throw ArithmeticException("") } else { return 10 / value } } fun func4(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } }
  • 227. Exception • partialFunction fun func(value: Int): Int { if(value == 0){ return -1 } else { return 10 / value } } fun func2(value: Int): Int? { if(value == 0){ return null } else { return 10 / value } } fun func3(value: Int): Int { if(value == 0){ return throw ArithmeticException("") } else { return 10 / value } } fun func4(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } }
  • 228. Exception • partialFunction fun func(value: Int): Int { if(value == 0){ return -1 } else { return 10 / value } } fun func2(value: Int): Int? { if(value == 0){ return null } else { return 10 / value } } fun func3(value: Int): Int { if(value == 0){ return throw ArithmeticException("") } else { return 10 / value } } fun func4(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } }
  • 229. Exception • partialFunction fun func(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } } fun func2(x: Int, y: Int): Int { return x * y }
  • 230. Exception • partialFunction fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = func2(result, b) println(result2) // -10 } fun func(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } } fun func2(x: Int, y: Int): Int { return x * y }
  • 231. Exception • partialFunction fun func(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } } fun func2(x: Int, y: Int): Int { return x * y } fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = func2(result, b) println(result2) // -10 }
  • 232. Exception • partialFunction fun func(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } } fun func2(x: Int, y: Int): Int { return x * y } fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = if (result != -1) { func2(result, b) } else { -1 } println(result2) // -1 }
  • 233. Exception • partialFunction fun func(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } } fun func2(x: Int, y: Int): Int { return try { x * y } catch (e: Exception) { -1 } } fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = if (result != -1) { func2(result, b) } else { -1 } println(result2) // -1 }
  • 234. Exception • partialFunction • -1을 예외상황에 사용한다면 실제값이 -1인 상황을 예외로 인식 할수 있다. • Null 이나 exception을 사용하면 순수함수라고 할 없으며, 비즈 니스 로직의 흐름이 끊겨버린다. • 앞의 결과를 다음 로직에 사용 하려면 항상 값 체크를 해줘야 한 다.
  • 236. Exception • Maybe sealed class Maybe<out T> data class Just<T>(val value: T) : Maybe<T>() object None : Maybe<Nothing>()
  • 237. Exception • Maybe sealed class Maybe<out T> data class Just<T>(val value: T) : Maybe<T>() object None : Maybe<Nothing>() • 값이 있으면 Just • 값이 없으면 None
  • 238. Exception • Maybe fun func(value: Int): Int { return try { 10 / value } catch (e: Exception) { -1 } }
  • 239. Exception • Maybe fun func(value: Int): Maybe<Int> { return try { Just(10 / value) } catch (e: Exception) { None } }
  • 241. Exception • Maybe fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = if (result != -1) { func2(result, b) } else { -1 } println(result2) // -1 }
  • 242. Exception • Maybe fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = when (result) { is Just -> func2(result.value, b) None -> None } when(result2){ is Just -> println(result2.value) None -> println("none") } }
  • 243. Exception • Maybe fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = when (result) { is Just -> func2(result.value, b) None -> None } when(result2){ is Just -> println(result2.value) None -> println("none") } }
  • 244. Exception • Maybe sealed class Maybe<out T> data class Just<T>(val value: T) : Maybe<T>() object None : Maybe<Nothing>()
  • 245. Exception • Maybe sealed class Maybe<out T> { abstract fun <R> map(transformer: (T) -> R): Maybe<R> } data class Just<T>(val value: T) : Maybe<T>() { override fun <R> map(transformer: (T) -> R): Just<R> = Just(transformer(value)) } object None : Maybe<Nothing>() { override fun <R> map(transformer: (Nothing) -> R): Maybe<R> = None }
  • 246. Exception • Maybe sealed class Maybe<out T> { abstract fun <R> map(transformer: (T) -> R): Maybe<R> } data class Just<T>(val value: T) : Maybe<T>() { override fun <R> map(transformer: (T) -> R): Just<R> = Just(transformer(value)) } object None : Maybe<Nothing>() { override fun <R> map(transformer: (Nothing) -> R): Maybe<R> = None }
  • 247. Exception • Maybe sealed class Maybe<out T> { abstract fun <R> map(transformer: (T) -> R): Maybe<R> } data class Just<T>(val value: T) : Maybe<T>() { override fun <R> map(transformer: (T) -> R): Just<R> = Just(transformer(value)) } object None : Maybe<Nothing>() { override fun <R> map(transformer: (Nothing) -> R): Maybe<R> = None }
  • 248. Exception • Maybe fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = if (result != -1) { func2(result, b) } else { -1 } println(result2) // -1 }
  • 249. Exception • Maybe fun main(args: Array<String>) { val a = 0 val result = func(a) val b = 10 val result2 = result.map { value -> func2(value, b) } when (result2) { is Just -> println(result2.value) None -> println("none") } }
  • 250. Exception • Maybe val result = func(0) val result2 = if (result != -1) { func2(result, 10) } else { -1 } val result3 = if (result2 != -1) { func2(result2, 0) } else { -1 } val result4 = if (result3 != -1) { func2(result3, 4) } else { -1 } println(result4) // -1
  • 251. Exception • Maybe val result = func(0) .map { func2(it, 10) } .map { func2(it, 0) } .map { func2(it, 4) } println(result) // -1
  • 252. 실습 • IntelliJ를 실행하고 GitHub 에서 소스 다운 • https://github.com/myeonginwoo/t-academy
  • 253. 실습 • head 를 추가하는 addHead를 추가하자.
  • 254. 실습 • head 를 추가하는 addHead를 추가하자. fun <T> FpList<T>.addHead(value: T): FpList<T> = when (this) { Nil -> Cons(value, Nil) is Cons -> Cons(value, this) }
  • 255. 실습 • FpList<Int>의 모든 요소들의 합을 구하는 sum 함수를 일반재귀, 꼬리재귀로 만들어보자.
  • 256. 실습 • FpList<Int>의 모든 요소들의 합을 구하는 sum 함수를 일반재귀, 꼬리재귀로 만들어보자. fun FpList<Int>.sum(): Int = when (this) { Nil -> 0 is Cons -> head + tail.sum() } tailrec fun FpList<Int>.tailrecSum(acc: Int): Int = when (this) { Nil -> acc is Cons -> tailrecSum(head + acc) }
  • 257. 실습 • FpList의 요소중 앞에서부터 n개를 제외하는 drop 함수를 만들자. • 요소의 개수가 n보다 크다면 요소의 빈리스트를 • 빈리스트면 n과 상관없이 빈리스트를 반환
  • 258. 실습 • FpList의 요소중 앞에서부터 n개를 제외하는 drop 함수를 만들자. • 요소의 개수가 n보다 크다면 요소의 빈리스트를 • 빈리스트면 n과 상관없이 빈리스트를 반환 tailrec fun <T> FpList<T>.drop(n: Int): FpList<T> = when(this){ Nil -> Nil is Cons -> when(n){ 0 -> this else -> tail.drop(n-1) } }
  • 259. 실습 • FpList의 요소중 앞에서부터 n개를 반환하는 take 함수를 만들자. • 요소의 개수가 n보다 작다면 요소의 개수만큼 반환 • 빈리스트면 n과 상관없이 빈리스트를 반환
  • 260. 실습 • FpList의 요소중 앞에서부터 n개를 반환하는 take 함수를 만들자. • 요소의 개수가 n보다 작다면 요소의 개수만큼 반환 • 빈리스트면 n과 상관없이 빈리스트를 반환 fun <T> FpList<T>.take(n: Int): FpList<T> = when (this) { Nil -> Nil is Cons -> when (n) { 0 -> Nil else -> Cons(head, tail.take(n - 1)) } } tailrec fun <T> FpList<T>.take(n: Int, acc: FpList<T>): FpList<T> = when (this) { Nil -> acc is Cons -> when (n) { 0 -> acc else -> tail.take(n - 1, acc.appendTail(head)) } }
  • 261. 실습 • 타입을 변환해주는 transformer 함수를 입력받아 다른 타입의 FpList로 반환해주는 map 함수를 일반 재귀와 꼬리재귀로 만들자.
  • 262. 실습 • 타입을 변환해주는 transformer 함수를 입력받아 다른 타입의 FpList로 반환해주는 map 함수를 일반 재귀와 꼬리재귀로 만들자. fun <T, R> FpList<T>.map(transformer: (T) -> R): FpList<R> = when (this) { Nil -> Nil is Cons -> Cons(transformer(head), tail.map(transformer)) } tailrec fun <T, R> FpList<T>.map(acc: FpList<R>, transformer: (T) -> R): FpList<R> = when (this) { Nil -> acc is Cons -> tail.map(acc.appendTail(transformer(head)), transformer) }
  • 263. 실습 • boolean을 반환하는 predicate 함수를 입력받아 요소들 중 참인 요소들만 걸러내는 filter 함수를 일반 재귀와 꼬리재귀로 만들자.
  • 264. 실습 • boolean을 반환하는 predicate 함수를 입력받아 요소들 중 참인 요소들만 걸러내는 filter 함수를 일반 재귀와 꼬리재귀로 만들자. fun <T> FpList<T>.filter(predicate: (T) -> Boolean): FpList<T> = when (this) { Nil -> Nil is Cons -> if (predicate(head)) { Cons(head, tail.filter(predicate)) } else { tail.filter(predicate) } } tailrec fun <T> FpList<T>.filter(acc: FpList<T>, predicate: (T) -> Boolean): FpList<T> when (this) { Nil -> acc is Cons -> if (predicate(head)) { tail.filter(acc.appendTail(head), predicate) } else { tail.filter(acc, predicate) } }
  • 265. • 사이드 이펙트를 방지 할 수 있습니다. • 일반적으로 코드가 간결해집니다. • 코드의 재활용성이 높아집니다. •  게으른 평가가 가능(LazyEvaluation) • 타입 추론이 가능 장점
  • 266. • 일반적으로 코드가 간결해집니다. 장점
  • 267. • 일반적으로 코드가 간결해집니다. 장점 fun unSimple(list: List<Int>): List<Int> { val evens = mutableListOf<Int>() for (elem in list) { if (elem % 2 == 0) { evens.add(elem) } } val result = mutableListOf<Int>() for (elem in evens) { result.add(elem * 10) } return result }
  • 268. • 일반적으로 코드가 간결해집니다. 장점 fun simple(list: List<Int>): List<Int> = list .filter { it % 2 == 0 } .map { it * 10 }
  • 269. • 일반적으로 코드가 간결해집니다. 장점 fun main(args: Array<String>) { val list = listOf(1, 2, 3, 4, 5) println(unSimple(list)) //[20, 40] println(simple(list)) //[20, 40] } fun unSimple(list: List<Int>): List<Int> { val evens = mutableListOf<Int>() for (elem in list) { if (elem % 2 == 0) { evens.add(elem) } } val result = mutableListOf<Int>() for (elem in evens) { result.add(elem * 10) } return result } fun simple(list: List<Int>): List<Int> = list .filter { it % 2 == 0 } .map { it * 10 }
  • 270. • 높은 일반화로 코드의 재활용성이 높아집니다. 장점
  • 271. • 높은 일반화로 코드의 재활용성이 높아집니다. 장점 @kotlin.internal.InlineOnly public inline fun <T, R> T.let(block: (T) -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block(this) }
  • 272. • 게으른 평가가 가능(LazyEvaluation) 장점
  • 273. • 게으른 평가가 가능(LazyEvaluation) 장점
  • 274. • 타입 추론이 가능 장점
  • 275. • 러닝커브가 높다. • 국내 레퍼런스가 적다. • 팀 전체가 관심있고 하려는 의지가 있어야 한다. • 언어차원에서 지원해줘야 한다. 단점
  • 276. • 러닝커브가 높다. 단점 0 25 50 75 100 시작 함수타입 고차함수 꼬리재귀 컬렉션 모나드 ...
  • 277. • 러닝커브가 높다. 단점 0 25 50 75 100 시작 함수타입 고차함수 재귀 컬렉션 모나드 ...
  • 278. • 국내 레퍼런스가 적다. 단점
  • 279. • 국내 레퍼런스가 적다. 단점 FunFunStudy https://github.com/funfunStudy/study/wiki myeonginwoo@gmail.com
  • 280. • 국내 레퍼런스가 적다. 단점 2019년 3월 함수형 프로그래밍 공동 저서 출간 예정!!!
  • 281. • 팀 전체가 관심있고 하려는 의지가 있어야 한다. 단점
  • 282. • 팀 전체가 관심있고 하려는 의지가 있어야 한다. 단점