- ์ฌ๊ท, ๊ณต์ฌ๊ท, ๊ผฌ๋ฆฌ ์ฌ๊ท ํจ์์ ๊ตฌํ ๋ฐฉ๋ฒ์ ์์๋ณธ๋ค.
- TCE๋ฅผ ์ฌ์ฉํด ๊ผฌ๋ฆฌ ์ฌ๊ท ํธ์ถ์ ์ต์ ํํ๋ค.
- ๋๋ค๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๋ง๋ ๋ค.
- memorization์ ์ ์ฉํด ๊ณ์ฐ ์๋๋ฅผ ๋์ธ๋ค.
- ์ฌ๊ท(recursive) : ๋ง์ง๋ง ๋จ๊ณ๋ถํฐ ๊ณ์ฐ์ ์์ํ๋ค.
- ๊ณต์ฌ๊ท(corecursive) : ํ ๋จ๊ณ์ ์ถ๋ ฅ์ ๋ค์ ๋จ๊ณ์ ์ ๋ ฅ์ผ๋ก ์ฌ์ฉํ๋ ๊ณ์ฐ ๋จ๊ณ๋ฅผ ํฉ์ฑํ ๊ฒ์ผ๋ก, ์ฒซ ๋จ๊ณ๋ถํฐ ๊ณ์ฐ์ ์์ํ๋ค.
- ์ด๊ธฐ ๋ฌธ์์ด s๋ก๋ถํฐ ์์ํด ํ๋จ๊ณ์ฉ ๋ณํ
fun append(s: String, c: Char) = "$s$c"
fun toString(list: List<Char>, s: String): String = if (list.isEmpty()) {
s
} else {
// toString(list.slice(1 until list.size), append(s, list[0]))
toString(list.drop(1), append(s, list.first())) // ๊ฐ์ ํํ
}
fun main(args: Array<String>) {
println(toString(listOf('1', '2', '3'), "abc")) // abc123
}
- List๋ง ์์ด๋ ๋๋๋ก ๊ฐ์ ํ๊ธฐ
- ์ฝํ๋ฆฐ์ ์์ ์ ํธ์ถํ๋ ํจ์์ ํ์ ์ ์ถ๋ก ํ ์ ์๋ค. ์์ชฝ ํจ์๋ ์๊ธฐ ์์ ์ ํธ์ถํ๋ ํจ์๋ผ ํ์ ์ ๋ช ์ํด์ผ ํ๋ค.
fun append(s: String, c: Char) = "$s$c"
fun toString(list: List<Char>): String {
fun toString(list: List<Char>, s: String): String = if (list.isEmpty()) {
s
} else {
toString(list.drop(1), append(s, list.first()))
}
return toString(list, "")
}
fun main(args: Array<String>) {
println(toString(listOf('1', '2', '3'))) // 123
}
๋ง์ฝ append ๋์ ์๋์ ๋ฉ์๋๋ง ์ฌ์ฉ ๊ฐ๋ฅํ๋ค๋ฉด?
fun prepend(s: String, c: Char) = "$c$s"
-
๊ณต์ฌ๊ท๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ ๊ฒฝ์ฐ, ๋ฆฌ์คํธ์ ์ฒซ๋ฒ์งธ ์์ ๋์ ๋ง์ง๋ง ์์๋ฅผ ์ด์ฉํด ๋จ๊ณ๋ณ๋ก ์งํํจ
๋ง์ฝ ๋ฆฌ์คํธ ๋์ ๋จ์ผ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ๋งค์ฐ ๋นํจ์จ์
fun toString(list: List<Char>, s: String): String = if (list.isEmpty()) { s } else { toString(list.subList(0, list.size - 1), prepend(s, list.last())) }
-
์ฌ๊ท๋ก ๊ตฌํํ ๊ฒฝ์ฐ
์ฌ๊ท๋ ์ต์ข ์กฐ๊ฑด(
list.isEmpty()
)์ ๋๋ฌํ๊ธฐ ์ ๊น์ง๋ ๊ณ์ฐ์ด ๋ฏธ๋ค์ง๊ณ , ์ค๊ฐ ๊ฒฐ๊ณผ๋ stack ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋๋ค.fun toString(list: List<Char>, s: String): String = if (list.isEmpty()) { s } else { prepend(toString(list.subList(1, list.size)), list.first()) }
ํจ์๊ฐ ๊ณ์ฐ์ ์ผ๋ถ๋ถ์ผ๋ก ์๊ธฐ ์์ ์ ํธ์ถํ๋ค๋ฉด ๊ทธ ํจ์๋ ์ฌ๊ท์ ์ด๋ค. ๊ทธ๋ ์ง ์๋ค๋ฉด ์๊ธฐ ์์ ์ ํธ์ถํ๋๋ผ๋ ์ง์ ํ ์ฌ๊ท ํจ์๊ฐ ์๋๋ค.
์๋์ ์ฝ๋๋ ์ฌ๊ท์ ์ธ ๋ฉ์๋๋ฅผ ํตํด ๊ตฌํํ์ง๋ง, ์ค์ ๋ก ์ด ํจ์๋ ๋ฌดํ ๋ฃจํ๋ก ๋ณํํ ์ ์๋ ๊ณต์ฌ๊ท ํจ์๋ค.
fun hello() {
hello()
}
๊ณต์ฌ๊ท์ ์ฌ๊ท์ ์ฐจ์ด์
- ๊ณต์ฌ๊ท์์๋ ๊ฐ ๋จ๊ณ๋ฅผ ์ฆ์ ๊ณ์ฐํ๋ค, ์ฌ๊ท ํจ์๋ ์ต์ข ์กฐ๊ฑด์ ๋๋ฌํ๊ณ ๋์ ์ด์ ๋จ๊ณ๋ฅผ ์ญ์์ผ๋ก ๊ณ์ฐํ๋ค. ๋ฉ๋ชจ๋ฆฌ์ ํ์ฌ ๊ณ์ฐ์ ํ์ํ ๊ฐ๋ง ์ ์ฅ๋๋ค.
- ์ฌ๊ท์์๋ ์ต์ข ์กฐ๊ฑด์ ๋๋ฌํ ๋ ๊น์ง ๋ชจ๋ ๋จ๊ณ๋ฅผ ์ด๋ค ํํ๋ก๋ ์ ์ฅํด์ผ ํ๋ค. ์ด๋ก ์ธํด ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ถ์กฑํด์ง ํ๋ฅ ์ด ๋๊ณ , ์ด ๋ฌธ์ ๋ฅผ ํผํ๋ ค๋ฉด ์ฌ๊ท ๋์ ๊ณต์ฌ๊ท๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ต์ ์ด๋ค.
์ค๊ฐ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ์ง๋ ์์ง๋ง ๊ณต์ฌ๊ท๋ ๊ฒฐ๊ตญ์ ์คํ ๊ณต๊ฐ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์, ๋๋ฆฌ๊ธด ํ์ง๋ง ์ธ์ ๊ฐ ์คํ์ ๊ณ ๊ฐ์ํฌ ๊ฐ๋ฅ์ฑ์ด ์๋ค. ์ด ๋ฌธ์ ๋ฅผ ์์ ํ ์ ๊ฑฐํ๊ธฐ ์ํด์ ๊ณต์ฌ๊ท๋ฅผ ์ผ๋ฐ์ ์ธ ๋ฃจํ๋ก ๋ฐ๊พธ๋ฉด ๋๋ค.
fun toString2(list: List<Char>): String {
var s = ""
for (c in list) {
s = append(s, c)
}
return s
}
์ฝํ๋ฆฐ์ ๋ ๊ณต์ฌ๊ท๋ฅผ ์๋์ผ๋ก ๋ฃจํ๋ก ๋ณํํด์ฃผ๋ ๊ธฐ๋ฅ์ด ์๋ค.
-
๊ผฌ๋ฆฌ ์ฌ๊ท ํธ์ถ : ์ฌ๊ท ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ๋ค๋ฅธ ์ฐ์ฐ์ ์ฌ์ฉํ์ง ์๊ณ ์ฆ์ ๋ฐํํ๋ ํจ์
์๊ธฐ ์์ ๋ง์ ํธ์ถํ๋ค๊ฐ ๊ฒฐ๊ณผ ๊ฐ์ ๋ฐํํ๋ ๊ตฌ์กฐ๋ก ๊ผฌ๋ฆฌ ์ฌ๊ท ํจ์ O
fun toString(list: List<Char>, s: String): String = if (list.isEmpty()) { s } else { toString(list.drop(1), append(s, list.first())) }
๊ฒฐ๊ณผ ๊ฐ์
trim()
์ด๋ผ๋ ์ถ๊ฐ์ ์ธ ์ฐ์ฐ์ ์ํํ๋ฏ๋ก ๊ผฌ๋ฆฌ ์ฌ๊ท ํจ์ Xfun toString(list: List<Char>, s: String): String = if (list.isEmpty()) { s } else { toString(list.drop(1), append(s, list.first())).trim() }
-
์ฝํ๋ฆฐ์์ ํจ์ ์์
tailrec
ํค์๋๋ฅผ ์์ ๋ถ์ด๋ฉด ๊ผฌ๋ฆฌ ํธ์ถ์ ์ ๊ฑฐํ ์ ์๋ค. ์ฌ๊ท ๋์ ๋ฃจํ๋ฅผ ์ฌ์ฉํ ์ฝ๋๋ก ๋ณ๊ฒฝ๋๋ค. -
tailrec์ ๋ถ์ด๊ณ ๋์ปดํ์ผ ํด๋ณด๊ธฐ
- Kotlin์ผ๋ก ์์ฑํ ์ฝ๋
tailrec fun toString(list: List<Char>, s: String): String = if (list.isEmpty()) { s } else { toString(list.drop(1), append(s, list.first())) }
- ๋์ปดํ์ผ ๊ฒฐ๊ณผ ์ฝํ๋ฆฐ์ด ์ด ํจ์๊ฐ ๊ผฌ๋ฆฌ ์ฌ๊ท์์ ๊ฐ์งํ๊ณ TCE๋ฅผ ์ ์ฉํ๋ค.
@NotNull public static final String toString(@NotNull List list, @NotNull String s) { while(true) { Intrinsics.checkParameterIsNotNull(list, "list"); Intrinsics.checkParameterIsNotNull(s, "s"); if (list.isEmpty()) { return s; } List var10000 = CollectionsKt.drop((Iterable)list, 1); s = append(s, (Character)CollectionsKt.first(list)); list = var10000; } }
์ฌ๊ท๊ฐ ๊ณต์ฌ๊ท๋ณด๋ค ๋ฉ๋ชจ๋ฆฌ ์ ์ฝ์ด ํฌ๋ค๋ ๋จ์ ์ด ์์ผ๋, ์ฌ๊ท์๋ ์ฝ๋ ์์ฑ์ด ๋จ์ํ๋ค๋ ์ฅ์ ์ด ์๋ค.
// 1..n๊น์ง์ ํฉ์ ๊ตฌํ๋ ํจ์
// ์ฌ๊ท๋ฅผ ์ฌ์ฉํ์ ๋
fun sum(n: Int): Int = if (n < 1) 0 else n + sum(n - 1)
// ๋ฃจํ๋ฅผ ์ฌ์ฉํ์ ๋
fun sum(n: Int): Int {
var result = 0
for (i in 0..n) {
result += n
}
return result
}
์๊ธฐ ์์ ์ ํธ์ถํ ๋๋ง๋ค s + i
์ i + 1
์ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋๊ฒจ์ฃผ๋ฉด ๊ณต์ฌ๊ท๋ก ๋ณํ์ด ๊ฐ๋ฅํ๋ค.
์์ tailrec์ ๋ถ์ฌ TCE๋ฅผ ์ ์ฉํ๋ฉด ๋ฃจํ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋์ผํ ๋์์ด ๋๋ค.
fun sum(n: Int): Int {
tailrec fun sum(s: Int, index: Int): Int =
if (index > n) s else sum(s + index, index + 1)
return sum(0, 0)
}
-
์ฐ์ต ๋ฌธ์ 4.1
์์ ์ ์์ ๋ํด ์๋ํ๋ ๊ณต์ฌ๊ท add ํจ์๋ฅผ ์์ฑํ๋ผ. add ๊ตฌํ์๋ +๋ -๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ค์ ๋ ํจ์๋ง ์ฌ์ฉํด์ผ ํ๋ค.
fun inc(n: Int) = n + 1 fun dec(n: Int) = n - 1
- loop๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ
fun add(a: Int, b: Int): Int { var x = a var index = b while (index > 0) { x = inc(x) index = dec(index) } return x }
- ๊ณต์ฌ๊ท๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ
tailrec fun add(a: Int, index: Int): Int = if (index > 0) { add(inc(a), dec(index)) } else { a }
-
์ฐ์ต ๋ฌธ์ 4.2
์ฌ๊ท์ ๊ณ์น ํจ์ ๊ฐ์ ์์ฑํ๋ผ. ํจ์ ๊ฐ์ val ํค์๋๋ก ์ ์๋ ํจ์๋ค.
- ์ง์ฐ์ด๊ธฐํ๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด ๋๋ค์ ๋ด๋ถ์์ factorial์ ์ฐธ์กฐํ ์ ์๋ค๋ ์ค๋ฅ๊ฐ ์ถ๋ ฅ๋๋ค. ์ปดํ์ผ๋ฌ๊ฐ factorial์ ์ ์ํ๋ ์ค๊ฐ์ ์์ง ์ ์๊ฐ ๋๋์ง ์์ factorial์ ํธ์ถํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ์ง์ฐ์ด๊ธฐํ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
val factorial: (Int) -> Int by lazy { { n: Int -> if (n <= 1) n else n * factorial(n - 1) } }
13๋ถํฐ๋ int๋ก ํํํ ์ ์๋ ๋ฒ์๋ฅผ ๋์ด๊ฐ๊ธฐ ๋๋ฌธ์ ์ ๋๋ก ์คํ๋์ง ์๋๋ค. ๋ง์ฝ ์ ๋๋ก ๋ ๊ฐ์ ์ํ๋ค๋ฉด Int ๋์
BigInteger
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
๋ฆฌ์คํธ๋ฅผ ์ฒ๋ฆฌํ ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฆฌ์คํธ๋ฅผ 0๋ฒ ์์
์ 0๋ฒ ์์๋ฅผ ์ ์ธํ ๋๋จธ์ง
๋ ๋ถ๋ถ์ผ๋ก ์ชผ๊ฐ์ ์ฒ๋ฆฌํ๋ค. 0๋ฒ ์์๋ฅผ head, ๋๋จธ์ง๋ฅผ tail์ด๋ผ ๋ถ๋ฅธ๋ค.
๋ฆฌ์คํธ์ ๋จธ๋ฆฌ์ ๊ผฌ๋ฆฌ๋ฅผ ๋๋ ค์ฃผ๋ ๋์ฐ๋ฏธ ํจ์๋ฅผ ์ ์ํ์.
fun <T> List<T>.head(): T = if (isEmpty()) {
throw IllegalArgumentException("head called on empty list")
} else {
this[0]
}
fun <T> List<T>.tail(): List<T> = if (isEmpty()) {
throw IllegalArgumentException("tail called on empty list")
} else {
drop(1)
}
- ์๊น ์ ์์ฑํ๋ toString()์ ํ์ฅ ํจ์ head(), tail()๋ฅผ ์ ์ฉํด์ ๋ ์ง๊ด์ ์ผ๋ก ํํํ ์ ์๋ค.
fun toString(list: List<Char>): String {
tailrec fun toString_(list: List<Char>, s: String): String =
if (list.isEmpty()) s else toString_(list.tail(), append(s, list.head()))
return toString_(list, "")
}
์ธ์ ํ์
์ด ๊ฐ์๋ ์ถฉ๋์ด ๋์ง ์๋๋ก, ์์ผ๋ก๋ ๋์ฐ๋ฏธ ํจ์๋ ์ฃผ ํจ์_
ํ์์ผ๋ก ๋ค์ด๋ฐ ํ๊ฒ ๋ค.
์ด์ค ์ฌ๊ท๋ ๋จ๊ณ๋ง๋ค ์์ ์ ๋ ๋ฒ ํธ์ถํ๋ ํจ์๋ฅผ ์๋ฏธํ๋ค.
-
ํผ๋ณด๋์น ์์ด์ ์ด์ค ์ฌ๊ท ํจ์๋ฅผ ์ค๋ช ํ๋ ๊ฐ์ฅ ๊ฐ๋จํ ์์ ๋ค.
fun fibonacci(n: Int): Int = if (n <= 1) 1 else fibonacci(n - 1) + fibonacci(n - 2)
ํ ๋ฒ ํจ์๋ฅผ ํธ์ถํ ๋๋ง๋ค 2๊ฐ์ ์ถ๊ฐ ํธ์ถ์ด ์๊ธฐ๊ธฐ ๋๋ฌธ์ f(n)์ ๊ณ์ฐํ๋ ค๋ฉด 2^n๊ฐ์ ์ฌ๊ท ํธ์ถ์ด ๋ฐ์ํ๋ค. ์ด๋ก์ธํด ์ซ์๊ฐ ์กฐ๊ธ๋ง ์ปค์ ธ๋ ์คํ ์๊ฐ์ด ๋ฌด์ง๋ง์งํ๊ฒ ๊ธธ์ด์ง๋ค.
-
4.3 ๊ผฌ๋ฆฌ ์ฌ๊ท ๋ฒ์ ์ ํผ๋ณด๋์น ํจ์๋ฅผ ๋ง๋ค๋ผ.
return ๋ฌธ์์
+
์ฐ์ฐ์ ์ง์ ์ ์ฉํ๋ฉด TCE ์ ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค. ๋ฐ๋ผ์ f(n - 1)๊ณผ f(n - 2)์ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋์ ํ๋ ์ธ์๋ฅผ ํ๋ ์ถ๊ฐํด์ผ ํ๋ค.fun fibonacci(x: Int): BigInteger { tailrec fun fib(n1: BigInteger, n2: BigInteger, x: BigInteger): BigInteger = when { (x == BigInteger.ZERO) -> BigInteger.ONE (x == BigInteger.ONE) -> n1 + n2 else -> fib(n2, n1 + n2, x - BigInteger.ONE) } return fib(BigInteger.ZERO, BigInteger.ONE, BigInteger.valueOf(x.toLong())) }
-
4.4 makeString์ ๊ผฌ๋ฆฌ ์ฌ๊ท ๋ฒ์ ์ ๋ง๋ค์ด๋ผ
fun <T> makeString(list: List<T>, delim: String): String { tailrec fun makeString_(list: List<T>, acc: String): String = when { list.isEmpty() -> acc acc.isEmpty() -> makeString_(list.tail(), "${list.head()}") else -> makeString_(list.tail(), "$acc$delim${list.head()}") } return makeString_(list, "") }
-
4.5 sum, toString, makeString์ ์ ์ํ ๋ ์ธ ์ ์๋ ๊ผฌ๋ฆฌ ์ฌ๊ท ์ ๋ค๋ฆญ ํจ์๋ฅผ ๋ง๋ค์ด๋ผ.
fun <T, U> foldLeft(list: List<T>, z: U, f: (U, T) -> U): U { tailrec fun foldLeft(list: List<T>, acc: U): U = if (list.isEmpty()) { acc } else { foldLeft(list.tail(), f(acc, list.head())) } return foldLeft(list, z) }
-
4.6 forLeft์ ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก, ๊ณต์ฌ๊ท ๋์ ์ฌ๊ท๋ฅผ ์ฌ์ฉํ๋ foldRight๋ฅผ ์์ฑํ๊ธฐ
fun <T, U> foldRight(list: List<T>, identity: U, f: (T, U) -> U): U = if (list.isEmpty()) { identity } else { f(list.head(), foldRight(list.tail(), identity, f)) } fun string(list: List<Char>): String = foldRight(list, "") { c, s -> prepend(c, s) }
-
4.7 fold๋ฅผ ์ฌ์ฉํด reverse ํจ์ ์ ์ํ๊ธฐ
fun <T> reverse(list: List<T>): List<T> = foldLeft(list, listOf(), { newList: List<T>, elem: T -> listOf(elem) + newList }) fun main(args: Array<String>) { println(reverse(listOf(1, 2, 3)).joinToString()) // 3, 2, 1 }
-
4.8 ๋ ๋ฆฌ์คํธ๋ฅผ ์ฐ๊ฒฐํ์ง ์๊ณ ,
๋ฆฌ์คํธ + ์์
๋ฅผ ์ฌ์ฉํด reverse ํจ์๋ฅผ ๋ง๋ค๊ธฐfun <T> prepend(list: List<T>, elem: T): List<T> = foldLeft(list, listOf(elem), { newList: List<T>, elm: T -> newList + elm }) fun <T> reverse(list: List<T>): List<T> = foldLeft(list, listOf(), ::prepend)
-
4.9 ์์, ๋, x โ x+1๋ก ๋ฆฌ์คํธ๋ฅผ ๋ง๋๋ ํจ์์ ๋ฃจํ ๊ธฐ๋ฐ ๊ตฌํ ์์ฑ
fun range(start: Int, end: Int): List<Int> { val result: MutableList<Int> = mutableListOf() var index = start while (index < end) { result.add(index) index++ } return result }
-
4.10 ์์์ ํ์ ๊ณผ ์กฐ๊ฑด์ ๋ํด์๋ง ์๋ํ๊ฒ 4.9 ์์
fun <T> unfold(seed: T, f: (T) -> T, p: (T) -> Boolean): List<T> { val result: MutableList<T> = mutableListOf() var elem = seed while (p(elem)) { result.add(elem) elem = f(elem) } return result }
-
4.11 4.10์ผ๋ก 4.9๋ฅผ ๊ตฌํ
fun range(start: Int, end: Int): List<Int> = unfold(start, { it + 1 }, { it < end })
-
4.12 4.9์ ์ฌ๊ท ๋ฒ์ ์ ์์ฑ
fun range(start: Int, end: Int): List<Int> = if (end <= start) listOf() else prepend(range(start + 1, end), start)
-
4.13 4.10์ ์ฌ๊ท ๋ฒ์ ์ ์์ฑ
fun <T> unfold(seed: T, f: (T) -> T, p: (T) -> Boolean): List<T> = if (p(seed)) prepend(unfold(f(seed), f, p), seed) else listOf()
-
4.14 4.10์ ๊ผฌ๋ฆฌ์ฌ๊ท ๋ฒ์ ์์ฑ
fun <T> unfold(seed: T, f: (T) -> T, p: (T) -> Boolean): List<T> { tailrec fun unfold_(acc: List<T>, seed: T): List<T> = if (p(seed)) unfold_(acc + seed, f(seed)) else acc return unfold_(listOf(), seed) }
๋ฉ๋ชจํ(memorization)๋ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํด ๋์ค์ ๊ฐ์ ๊ณ์ฐ์ ๋ค์ ์ํํ์ง ์๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ก ๋ฐํํ๋ ๊ธฐ๋ฒ์ด๋ค. ์ด๋ค ๊ณ์ฐ ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฌ๋ฒ ํ์ํ ๋ ๊ณ์ฐ์ ๋ฐ๋ณตํ์ง ์๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
fun fibonacciLoop(n: Int): Int {
var first = 1
var second = 1
return when (n) {
1 -> first
2 -> second
else -> {
var current = first + second
for (num in 3..n) {
current = first + second
first = second // f(n - 1)์ ์ ์ฅ
second = current // f(n)์ ์ ์ฅ
}
current
}
}
}
์ด๋ฐ ๊ธฐ๋ฒ์ ์์ ํ ํ๋ก๊ทธ๋๋ฐ ์์น์ ์๋ฐฐํ๋ ๊ฒ์ฒ๋ผ๋ ๋ณด์ธ๋ค. ํจ์๋ฅผ ๋ฉ๋ชจํํ๋ ค๋ฉด ์ํ๋ฅผ ์ ์งํด์ผ ํ๋๋ฐ, ์ด ์ํ๊ฐ ๋ถ์ ํจ๊ณผ์ ํด๋นํ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ฌ๋ ๊ฐ์ ์ธ์๋ฅผ ์ฌ์ฉํ๋ฉด ํญ์ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์ค๋ฏ๋ก, ์์ ํ ํ๋ก๊ทธ๋๋ฐ ์์น์ ์๋ฐํ์ง ์๋๋ค.
fun fibo(number: Int): String {
tailrec fun fibo_(
acc: List<BigInteger>,
acc1: BigInteger,
acc2: BigInteger,
x: BigInteger
): List<BigInteger> =
when (x) {
BigInteger.ZERO -> acc
BigInteger.ONE -> acc + (acc1 + acc2)
else -> fibo_(acc + (acc1 + acc2), acc2, acc1 + acc2, x - BigInteger.ONE)
}
val list = fibo_(listOf(), BigInteger.ONE, BigInteger.ZERO, BigInteger.valueOf(number.toLong()))
return list.joinToString()
}
ํผ๋ณด๋์น ์์ด 1, 1, 2, 3, 5, 8...์ ๋ค์๊ณผ ๊ฐ์ด ํํ์ ์งํฉ์ผ๋ก๋ ๋ณผ ์ ์๋ค.
(1, 1), (2, 3), (5, 8)... ํํ๋ก๋ถํฐ ๋ค์ ํํ์ ๋ง๋ค์ด๋ผ ์ ์๋ค.
val fibo = { (a, b): Pair<BigInteger, BigInteger> -> Pair(b, a + b)}
-
4.16 unfold์ฒ๋ผ ์๋ํ๋ iterate ํจ์๋ฅผ ์์ฑํ๋ผ
fun <T> iterate(seed: T, f: (T) -> T, n: Int): List<T> { tailrec fun iterate_(acc: List<T>, seed: T): List<T> = if (acc.size < n) { iterate_(acc + seed, f(seed)) } else { acc } return iterate_(listOf(), seed) }
-
4.17 T โ U ํ์ ํจ์๋ฅผ List ํ์ ๋ฆฌ์คํธ์ ๋ชจ๋ ์์์ ์ ์ฉํด ๋ง๋ List ํ์ ์ ๋ฆฌ์คํธ๋ฅผ ๋๋ ค์ฃผ๋ map ํจ์๋ฅผ ๋ง๋ ๋ค.
fun <T, U> map(list: List<T>, f: (T) -> U): List<U> { tailrec fun map_(acc: List<U>, list: List<T>): List<U> = if (list.isEmpty()) { acc } else { map_(acc + f(list.head()), list.tail()) } return map_(listOf(), list) }
ํ ๋ฒ ๊ณ์ฐํ ์ ์ด ์๋ ๊ฐ์ด๋ผ๋ฉด, ์บ์์ ์ ์ฅํด ๋๋ค๊ฐ ๋๊ฐ์ ๊ณ์ฐ์ด ๋ฐ๋ณต๋ ๋ ๊บผ๋ด ์ฐ๋ฉด ๋จ
์ ๋ ฅ์ ๊ฐ์ง์๊ฐ ๋ง์ง ์๋ค๋ฉด ๋ชจ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํด๋ ๋๋, ๋ง์ฝ ๊ฐ์ง์๊ฐ ๋ง๋ค๋ฉด ์ํํธ ์ฐธ์กฐ๋ ์ฝํ ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
class Memoizer<T, U> private constructor() {
private val cache = ConcurrentHashMap<T, U>()
private fun doMemoize(function: (T) -> U): (T) -> U = { input ->
cache.computeIfAbsent(input) {ย ย ย ย
function(it)
}
}
companion object {
fun <T, U> memoize(function: (T) -> U): (T) -> U =ย ย ย ย
Memoizer<T, U>().doMemoize(function)
}
}
fun longComputation(number: Int): Int {
println("๊ณ์ฐ ์คํ")
return number
}
fun main(args: Array<String>) {
val memoizedLongComputation = Memoizer.memoize(::longComputation)
val result1 = memoizedLongComputation(43)
val result2 = memoizedLongComputation(43)
}
// ์คํ ๊ฒฐ๊ณผ "๊ณ์ฐ ์คํ"์ด 1ํ ์ถ๋ ฅ๋๋ค.
3์ฅ์์ ์๊ธฐํ๋ฏ ๋ค์ธ์ ํจ์๋ ์กด์ฌํ์ง ์๋๋ค. ์ฌ๋ฌ ์ธ์๋ฅผ ๋ฐ๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ ํจ์๋ ๋ ์ค ํ๋์ ์ํ๋ค
- ํํ์ ํจ์ : ์ธ์๋ก
Pair
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. - ํจ์๋ฅผ ๋ฐํํ๋ ํจ์๋ฅผ ๋ฐํํ๋... ์ปค๋ฆฌ๋ ํจ์ : ์ปค๋ฆฌํ ํจ์์ ๊ฐ ๋จ๊ณ๊ฐ ๋ฐํํ๋ ํจ์๋ฅผ ๊ฐ๊ฐ ๋ฉ๋ชจํ ํด์ผํ๋ค.
val f3 = { x: Int -> { y: Int -> { z: Int -> x + y - z } } }
// ์ธ์๊ฐ 3๊ฐ์ธ ํจ์ ๋ฉ๋ชจํ
val f3m = Memoizer.memoize { x: Int ->
Memoizer.memoize { y: Int ->
Memoizer.memoize { z: Int -> x + y - z }
}
}
๋ฉ๋ชจํํ ํจ์๋ ์ธ์๊ฐ ๊ฐ์ผ๋ฉด ํญ์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ด๋๋๋ค. ๋จ์ง ๊ฒฐ๊ด๊ฐ์ ๋ฐํํ๋๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ด ๋ฌ๋ผ์ง ๋ฟ์ด๋ค. ์๋ ํจ์๊ฐ ์์ ํจ์๋ผ๋ฉด ๋ฉ๋ชจํํ ํจ์๋ ์์ ํจ์๋ค.