Upgrade to Pro — share decks privately, control downloads, hide ads and more …

関数型まつり2025登壇資料「関数プログラミングと再帰」

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 関数型まつり2025登壇資料「関数プログラミングと再帰」

Avatar for Taison Tsukada

Taison Tsukada

June 14, 2025
Tweet

Other Decks in Programming

Transcript

  1. 17

  2. 木構造の場合 このような単純な木構造があるとする type 'a Tree = | Leaf of 'a

    | Node of 'a Tree * 'a Tree 例: Node (Leaf 1, Node(Leaf 2, Leaf 3)) Node / \ Leaf(1) Node /  \ Leaf(2) Leaf(3) 21
  3. 23

  4. そんなときに継続渡しスタイル(CPS) 「次に何をするか」という関数を再帰呼び出しの引数に渡していく。 ここでいう cont は継続で「残りの計算」を表す。 これは末尾再帰になっていて、スタックには追加されない。 let map f tree

    = let rec mapInner tree cont = match tree with | Leaf x -> Leaf(f x) |> cont | Node (left, right) -> mapInner left (fun leftResult -> mapInner right (fun rightResult -> Node(leftResult, rightResult) |> cont)) mapInner tree id 24
  5. Node (Leaf 1, Leaf 2) を例になにが起こっているのかを紐解いていく。 let map f tree

    = let rec mapInner tree cont = match tree with | Leaf x -> Leaf(f x) |> cont | Node (left, right) -> mapInner left (fun leftResult -> mapInner right (fun rightResult -> Node(leftResult, rightResult) |> cont)) mapInner tree id > map ((*) 2) (Node (Leaf 1, Leaf 2));; val it: int Tree = Node (Leaf 2, Leaf 4) 25
  6. 初回の再帰呼出し 補助関数の引数の状態 tree: Node (Leaf 1, Leaf 2) cont: id

    初回はNodeのパターンに入る。 mapInner を left とそれ以降の計算を引数に再帰呼 出しをする let map f tree = let rec mapInner tree cont = match tree with | Leaf x -> Leaf(f x) |> cont | Node (left, right) -> //このケースに入る mapInner left (fun leftResult -> mapInner right (fun rightResult -> Node(leftResult, rightResult) |> cont)) mapInner tree id 26
  7. 2回目の再帰呼出し 補助関数の引数の状態 tree: Leaf 1 cont: (fun leftResult -> mapInner

    right (fun rightResult -> Node(leftResult, rightResult) |> id 2回目は Leaf のパターン。引数で受け取った関数 f を適用して cont を呼ぶ。 let map f tree = let rec mapInner tree cont = match tree with | Leaf x -> //このケースに入る Leaf(f x) |> cont | Node (left, right) -> mapInner left (fun leftResult -> mapInner right (fun rightResult -> Node(leftResult, rightResult) |> cont)) mapInner tree id 27
  8. cont を呼び出した結果 Leaf 2 |> (fun leftResult -> mapInner right

    (fun rightResult -> Node(leftResult, rightResult) |> id)) mapInner right (fun rightResult -> Node(Leaf 2, rightResult) |> id) 28
  9. 3回目の再帰呼び出し。 補助関数の引数の状態 tree: Leaf 2 cont: (fun rightResult -> Node(Leaf

    2, rightResult) |> id) 今回も Leaf のケースに入る let map f tree = let rec mapInner tree cont = match tree with | Leaf x -> //このケースに入る Leaf(f x) |> cont | Node (left, right) -> mapInner left (fun leftResult -> mapInner right (fun rightResult -> Node(leftResult, rightResult) |> cont)) mapInner tree id 29
  10. contを呼び出した結果 Leaf 4 |> (fun rightResult -> Node(Leaf 2, rightResult)

    |> id) Node(Leaf 2, Leaf 4) |> id Node(Leaf 2, Leaf 4) 30
  11. 改めて全体像 let map f tree = let rec mapInner tree

    cont = match tree with | Leaf x -> Leaf(f x) |> cont | Node (left, right) -> mapInner left (fun leftResult -> mapInner right (fun rightResult -> Node(leftResult, rightResult) |> cont)) mapInner tree id 31
  12. 36

  13. 基準の要素をfirst、それより小さい要素のリストと大きい要素のリストを作り、更にそ れらに対して再帰呼出しをする let rec quickSort lst = match lst with

    | [] -> [] | first :: rest -> let smaller, greater = List.partition ((>=) first) let sourtedSmaller = quickSort smaller let sourtedGreater = quickSort greater failwith "TODO" 39
  14. それぞれの結果を結合させる let rec quickSort lst = match lst with |

    [] -> [] | first :: rest -> let smaller, greater = List.partition ((>=) first) rest quickSort smaller @ [first] @ quickSort greater 40
  15. クイックソートを実装できた let rec quickSort lst = match lst with |

    [] -> [] | first :: rest -> let smaller, greater = List.partition ((>=) first) rest quickSort smaller @ [first] @ quickSort greater 41
  16. 継続渡しスタイル版 let quickSort lst = let rec inner lst cont

    = match lst with | [] -> cont [] | first :: rest -> let smaller, greater = List.partition ((>=) first) rest inner smaller (fun s -> inner greater (fun g -> cont (s @ [first] @ g))) inner lst id 42
  17. 参考 https://fsharpforfunandprofit.com/posts/computation-expressions-conts/ https://practical-scheme.net/docs/cont-j.html 浅井健一(2007) 『プログラミングの基礎』 (Computer Science Library 3) 、サイ

    エンス社. Stuart Halloway, Aaron Bedra(2013) 『プログラミングClojure 第2版』 、オーム社、 (原著:Stuart Halloway and Aaron Bedra, "Programming Clojure, 2nd edition", Pragmatic Bookshelf 2012、翻訳:川合史朗). Michał Płachta(2023) 『なっとく!関数型プログラミング』 、翔泳社、 (原著: Michał Płachta, "Grokking Functional Programming", Manning Publications 2022、翻 訳/監修:株式会社クイープ). 44