|
274 | 274 | "아래 cp''는 cp'와 동일한 성능을 가진다.\n",
|
275 | 275 | "\n",
|
276 | 276 | " cp'' [] = [[]]\n",
|
277 |
| - " cp'' (x:xss) = [x:ys | x <- xs, ys <- yss]\n", |
| 277 | + " cp'' (xs:xss) = [x:ys | x <- xs, ys <- yss]\n", |
278 | 278 | " where yss = cp xss"
|
279 | 279 | ]
|
280 | 280 | },
|
281 | 281 | {
|
282 | 282 | "cell_type": "markdown",
|
283 | 283 | "metadata": {},
|
284 | 284 | "source": [
|
285 |
| - "# 7.4 Analysing time" |
| 285 | + "# 7.4 Analysing time\n", |
| 286 | + "\n", |
| 287 | + "* 시간 복잡도는 expression의 속성이지 value의 속성은 아니다.\n", |
| 288 | + "* GHCi에서는 reduction step이 아닌 소요시간만을 측정한다. reduction 단계는 소요 시간과 반드시 일치하지는 않는다.\n", |
| 289 | + "* 상황에 따라서 다른 측정 방법이 필요하다. 예를 들면 concat xss의 경우 n보다는 (m,n)이 적합하다.\n", |
| 290 | + "* 시간 복잡도 측정은 eager evaluation으로 행한다. lazy evaluation은 측정이 어려우며 일반적으로 eager evaluation의 time이 lazy evaluation의 time 보다 tight boundary를 가진다.\n", |
| 291 | + "\n", |
| 292 | + "## Concat\n", |
| 293 | + "\n", |
| 294 | + " concat xss = foldr (++) [] xss\n", |
| 295 | + " concat' xss = foldl (++) [] xss\n", |
| 296 | + "\n", |
| 297 | + "T(++)(n,m) = $Ө(n)$임\n", |
| 298 | + "\n", |
| 299 | + "* concat: 길이 n의 리스트를 m회 (++) 함 $\\Theta (mn)$\n", |
| 300 | + "* concat': mn으로 증가하는 accumulator를 n회 (++) 함. $\\Theta (m^2 n$)\n", |
| 301 | + "\n", |
| 302 | + "concat은 foldr로 구현하는 것이 더 효율적임. foldl/foldr/foldl'이 적합한 경우가 다르다.\n", |
| 303 | + "\n", |
| 304 | + "## subseq\n", |
| 305 | + "\n", |
| 306 | + " subseqs (x:xs) = subseqs xs ++ map (x:) (subseqs xs)\n", |
| 307 | + " subseqs' (x:xs) = xss ++ map (x:) xss\n", |
| 308 | + " where xss = subseqs' xs\n", |
| 309 | + "\n", |
| 310 | + "map (x:)는 $\\Theta (2^n)$이므로 \n", |
| 311 | + "\n", |
| 312 | + "* $T(subseqs)(n+1) = 2T(subseqs)(n) + \\Theta (2^n) \\rightarrow T(subseqs)(n) = \\Theta (n 2^n)$\n", |
| 313 | + "* $T(subseqs')(n+1) = T(subseqs')(n) + \\Theta (2^n) \\rightarrow T(subseqs')(n) = \\Theta (2^n)$\n", |
| 314 | + "\n", |
| 315 | + "subseqs'가 logarithmic factor로 더 빠르다. 속도가 중요한 경우 common subexpression elimination을 잘 활용하자.\n", |
| 316 | + "\n", |
| 317 | + "## cartesian product\n", |
| 318 | + "\n", |
| 319 | + " cp [] = [[]]\n", |
| 320 | + " cp (xs:xss) = [x:ys | x <- xs, ys <- cp xss]\n", |
| 321 | + " cp' = foldr op [[]]\n", |
| 322 | + " where op xs yss = [x:ys | x <- xs, ys <- yss]\n", |
| 323 | + "\n", |
| 324 | + "cp에서 cp xss가 $\\Theta (n^m)$ 이고 m회만큼 반복하게 된다.\n", |
| 325 | + "\n", |
| 326 | + "* $T(cp)(m,n) = \\Theta (m n^m)$\n", |
| 327 | + "* $T(cp')(m,n) = \\Theta (n^m)$\n", |
| 328 | + "\n", |
| 329 | + "cp'가 logarithmic factor로 더 빠르다." |
286 | 330 | ]
|
287 | 331 | },
|
288 | 332 | {
|
289 | 333 | "cell_type": "markdown",
|
290 | 334 | "metadata": {},
|
291 | 335 | "source": [
|
292 |
| - "# 7.5 Accumulating Parameter" |
| 336 | + "# 7.5 Accumulating Parameter\n", |
| 337 | + "\n", |
| 338 | + "argument를 추가로 사용하여 속도를 향상시키는 것을 accumulating parameter라고 한다.\n", |
| 339 | + "\n", |
| 340 | + "## reverse\n", |
| 341 | + "\n", |
| 342 | + " reverse [] = []\n", |
| 343 | + " reverse (x:xs) = reverse xs ++ [x]\n", |
| 344 | + "\n", |
| 345 | + "++가 $\\Theta (n)$이고 n번 재귀를 하므로 T(reverse)(n)은 $\\theta (n^2)$ 이다.\n", |
| 346 | + "\n", |
| 347 | + " revcat :: [a] -> [a] -> [a]\n", |
| 348 | + " revcat xs ys = reverse xs ++ ys\n", |
| 349 | + "\n", |
| 350 | + "revcat은 accumulator를 사용해서 (++) 대신 (:) 을 사용한 것과 동일해짐. 따라서 $\\theta (n)$ 임\n", |
| 351 | + "\n", |
| 352 | + " [x] ++ xs = x:xs\n", |
| 353 | + "\n", |
| 354 | + "## length\n", |
| 355 | + "\n", |
| 356 | + " length :: [a] -> Int\n", |
| 357 | + " length [] = 0\n", |
| 358 | + " length (x:xs) = length xs + 1\n", |
| 359 | + " \n", |
| 360 | + " lenplus :: [a] -> Int -> Int\n", |
| 361 | + " lenplus [] n = n\n", |
| 362 | + " lenplus (x:xs) n = lenplus xs (1+n)\n", |
| 363 | + "\n", |
| 364 | + "time은 $\\Theta (n)$으로 동일하다. length는 space가 $\\Theta (n)$으로 증가하나 lenplus는 $\\Theta (1)$ 이다. (haskell의 length는 lenplus처럼 구현됨.)\n", |
| 365 | + "\n", |
| 366 | + "## tree\n", |
| 367 | + "\n", |
| 368 | + " data GenTree a = Node a [GenTree a]\n", |
| 369 | + " \n", |
| 370 | + " labels :: GenTree a -> [a]\n", |
| 371 | + " labels (Node x ts) = x:concat (map labels ts)\n", |
| 372 | + " \n", |
| 373 | + " 1\n", |
| 374 | + " / \\\n", |
| 375 | + " 2 3 labels = \"123\"\n", |
| 376 | + "\n", |
| 377 | + "> $T(labels)(1,k) = \\Theta(1)$\n", |
| 378 | + "> $T(labels)(h+1,k) = \\Theta(1) + T(concat)(k,s) + T(map labels)(h,k)$\n", |
| 379 | + "\n", |
| 380 | + "각 높이에서 k개의 subtree에 대해서 map labels가 수행되고 이것들을 concat해야됨. \n", |
| 381 | + "\n", |
| 382 | + "$$T(labels)(h+1,k) = \\Theta(k^{h+1}) + k T(labels)(h,k)$$\n", |
| 383 | + "\n", |
| 384 | + "따라서 $s = k^h$일때 $\\Theta (s \\log s)$ 임.\n", |
| 385 | + "\n", |
| 386 | + " labcat :: [GenTree a] -> [a] -> [a]\n", |
| 387 | + " labcat ts xs = concat (map labels ts) ++ xs\n", |
| 388 | + "\n", |
| 389 | + " labcat (Node x us:vs) xs\n", |
| 390 | + " = {definition}\n", |
| 391 | + " concat (map labels (Node x us:vs)) ++ xs\n", |
| 392 | + " = {definitions}\n", |
| 393 | + " labels (Node x us) ++ concat (map labels vs) ++ xs\n", |
| 394 | + " = {definiton}\n", |
| 395 | + " x:concat (map labels us) ++ concat (map labels vs) ++ xs\n", |
| 396 | + " = {definition of labcat}\n", |
| 397 | + " x:concat (map labels us) ++ labcat vs xs\n", |
| 398 | + " = {definition of labcat (again)}\n", |
| 399 | + " x:labcat us (labcat vs xs)\n", |
| 400 | + "\n", |
| 401 | + " labels' t = labcat [t] []\n", |
| 402 | + " labcat' [] xs = xs\n", |
| 403 | + " labcat' (Node x us:vs) = x:labcat' us (labcat' vs xs)\n", |
| 404 | + "\n", |
| 405 | + "* $T(labcat)(1,k,n) = \\Theta (n)$\n", |
| 406 | + "* $T(labcat)(h,k,n) = \\Theta (k^h n)$\n", |
| 407 | + "* tree size $s = k^h$\n", |
| 408 | + "\n", |
| 409 | + "따라서 $T(labels)(h,k) = T(labcat)(h,k,1) = \\Theta (s)$" |
293 | 410 | ]
|
294 | 411 | },
|
295 | 412 | {
|
296 | 413 | "cell_type": "markdown",
|
297 | 414 | "metadata": {},
|
298 | 415 | "source": [
|
299 |
| - "# 7.6 Tupling" |
| 416 | + "# 7.6 Tupling\n", |
| 417 | + "\n", |
| 418 | + "# fibonacci\n", |
| 419 | + "\n", |
| 420 | + " fib :: Int -> Integer\n", |
| 421 | + " fib 0 = 0\n", |
| 422 | + " fib 1 = 1\n", |
| 423 | + " fib n = fib (n-1) + fib (n-2)\n", |
| 424 | + "\n", |
| 425 | + "$T(fib)(n) = \\Theta (\\phi ^ n)$ 이며 golden ratio $\\phi = (1 + \\sqrt{5}) / 2$\n", |
| 426 | + "\n", |
| 427 | + " fib' 0 = (0,1)\n", |
| 428 | + " fib' n = (b,a+b) where (a,b) = fib' (n-1)\n", |
| 429 | + "\n", |
| 430 | + "fib는 exponential time이나 fib'는 linear time임.\n", |
| 431 | + "\n", |
| 432 | + "## general law for tupling\n", |
| 433 | + "\n", |
| 434 | + " (foldr f a xs, foldr g b xs) = foldr h (a,b) xs\n", |
| 435 | + " h x (y,z) = (f x y, g x z)" |
300 | 436 | ]
|
301 | 437 | },
|
302 | 438 | {
|
|
312 | 448 | "collapsed": false
|
313 | 449 | },
|
314 | 450 | "source": [
|
| 451 | + "# Conclusion\n", |
| 452 | + "\n", |
| 453 | + "functional programming에서 performance와 efficiency에 그 동안 궁금했던 것들을 조금은 해결할 수 있었다. 그러나 알면 알수록 functional programming으로 좋은 코드를 작성하는 것이 쉽지 않다는 생각이 든다.\n", |
| 454 | + "\n", |
315 | 455 | "\n",
|
316 | 456 | "# Reference\n",
|
317 | 457 | "\n",
|
|
0 commit comments