pfds 10.1.1 多相再帰
DESCRIPTION
TRANSCRIPT
![Page 1: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/1.jpg)
PFDS 10.1.1 多相再帰PFDS 10.1.1 多相再帰PFDS 10.1.1 多相再帰PFDS 10.1.1 多相再帰PFDS 10.1.1 多相再帰
Kiwamu OkabeKiwamu OkabeKiwamu OkabeKiwamu OkabeKiwamu Okabe
![Page 2: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/2.jpg)
多相再帰って何?多相再帰って何?多相再帰って何?多相再帰って何?多相再帰って何?
再帰を一つ進める前と後とで型が異なること。再帰を一つ進める前と後とで型が異なること。再帰を一つ進める前と後とで型が異なること。再帰を一つ進める前と後とで型が異なること。再帰を一つ進める前と後とで型が異なること。datatype a Seq = NIL' | CONS' of a * (a * a) Seq
fun sizeS NIL' = 0 | sizeS (CONS' (x, ps)) = 1 + 2 * sizeS ps
datatype a Seq = NIL' | CONS' of a * (a * a) Seq
fun sizeS NIL' = 0 | sizeS (CONS' (x, ps)) = 1 + 2 * sizeS ps
datatype a Seq = NIL' | CONS' of a * (a * a) Seq
fun sizeS NIL' = 0 | sizeS (CONS' (x, ps)) = 1 + 2 * sizeS ps
datatype a Seq = NIL' | CONS' of a * (a * a) Seq
fun sizeS NIL' = 0 | sizeS (CONS' (x, ps)) = 1 + 2 * sizeS ps
datatype a Seq = NIL' | CONS' of a * (a * a) Seq
fun sizeS NIL' = 0 | sizeS (CONS' (x, ps)) = 1 + 2 * sizeS ps
sizeS関数の型は...sizeS関数の型は...sizeS関数の型は...sizeS関数の型は...sizeS関数の型は...
☆ 左辺 => sizeS: a Seq -> int☆ 左辺 => sizeS: a Seq -> int☆ 左辺 => sizeS: a Seq -> int☆ 左辺 => sizeS: a Seq -> int☆ 左辺 => sizeS: a Seq -> int
☆ 右辺 => sizeS: (a * a) Seq -> int☆ 右辺 => sizeS: (a * a) Seq -> int☆ 右辺 => sizeS: (a * a) Seq -> int☆ 右辺 => sizeS: (a * a) Seq -> int☆ 右辺 => sizeS: (a * a) Seq -> int
![Page 3: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/3.jpg)
SMLで書きたい...んだけどSMLで書きたい...んだけどSMLで書きたい...んだけどSMLで書きたい...んだけどSMLで書きたい...んだけど
PFDSによるとStandard MLでは...PFDSによるとStandard MLでは...PFDSによるとStandard MLでは...PFDSによるとStandard MLでは...PFDSによるとStandard MLでは...
☆ 多相的なデータ型を定義することは可能☆ 多相的なデータ型を定義することは可能☆ 多相的なデータ型を定義することは可能☆ 多相的なデータ型を定義することは可能☆ 多相的なデータ型を定義することは可能
☆ 多相再帰を書くことは不可能☆ 多相再帰を書くことは不可能☆ 多相再帰を書くことは不可能☆ 多相再帰を書くことは不可能☆ 多相再帰を書くことは不可能
SML# や SML/NJ はどーなのか気になりますね。 (すいません試してないです)SML# や SML/NJ はどーなのか気になりますね。 (すいません試してないです)SML# や SML/NJ はどーなのか気になりますね。 (すいません試してないです)SML# や SML/NJ はどーなのか気になりますね。 (すいません試してないです)SML# や SML/NJ はどーなのか気になりますね。 (すいません試してないです)
![Page 4: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/4.jpg)
多相再帰=>単相再帰多相再帰=>単相再帰多相再帰=>単相再帰多相再帰=>単相再帰多相再帰=>単相再帰datatype a Seq = NIL' | CONS' of a * (a * a) Seqdatatype a Seq = NIL' | CONS' of a * (a * a) Seqdatatype a Seq = NIL' | CONS' of a * (a * a) Seqdatatype a Seq = NIL' | CONS' of a * (a * a) Seqdatatype a Seq = NIL' | CONS' of a * (a * a) Seq
↓単相へ変換↓単相へ変換↓単相へ変換↓単相へ変換↓単相へ変換datatype a EP = ELEM of a | PAIR of a EP * a EPdatatype a Seq = NIL' | CONS' of a EP * a Seqdatatype a EP = ELEM of a | PAIR of a EP * a EPdatatype a Seq = NIL' | CONS' of a EP * a Seqdatatype a EP = ELEM of a | PAIR of a EP * a EPdatatype a Seq = NIL' | CONS' of a EP * a Seqdatatype a EP = ELEM of a | PAIR of a EP * a EPdatatype a Seq = NIL' | CONS' of a EP * a Seqdatatype a EP = ELEM of a | PAIR of a EP * a EPdatatype a Seq = NIL' | CONS' of a EP * a Seq
のように多相再帰=>単相再帰への変換が必ず可能です。のように多相再帰=>単相再帰への変換が必ず可能です。のように多相再帰=>単相再帰への変換が必ず可能です。のように多相再帰=>単相再帰への変換が必ず可能です。のように多相再帰=>単相再帰への変換が必ず可能です。
![Page 5: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/5.jpg)
それなら全部単相再帰で書くべき?それなら全部単相再帰で書くべき?それなら全部単相再帰で書くべき?それなら全部単相再帰で書くべき?それなら全部単相再帰で書くべき?
それはもったいない!それはもったいない!それはもったいない!それはもったいない!それはもったいない!
☆ 多相にすれば型宣言を2つ=>1つに削減できた☆ 多相にすれば型宣言を2つ=>1つに削減できた☆ 多相にすれば型宣言を2つ=>1つに削減できた☆ 多相にすれば型宣言を2つ=>1つに削減できた☆ 多相にすれば型宣言を2つ=>1つに削減できた
☆ a EP型へのパターンマッチが不要で、そのコンストラクタをメモリに置く必要がない☆ a EP型へのパターンマッチが不要で、そのコンストラクタをメモリに置く必要がない☆ a EP型へのパターンマッチが不要で、そのコンストラクタをメモリに置く必要がない☆ a EP型へのパターンマッチが不要で、そのコンストラクタをメモリに置く必要がない☆ a EP型へのパターンマッチが不要で、そのコンストラクタをメモリに置く必要がない
☆ 多相にすれば、Seqの段数とペアの数が一致することを型が保証してくれる☆ 多相にすれば、Seqの段数とペアの数が一致することを型が保証してくれる☆ 多相にすれば、Seqの段数とペアの数が一致することを型が保証してくれる☆ 多相にすれば、Seqの段数とペアの数が一致することを型が保証してくれる☆ 多相にすれば、Seqの段数とペアの数が一致することを型が保証してくれる
![Page 6: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/6.jpg)
OCamlだとOCamlだとOCamlだとOCamlだとOCamlだとtype 'a my_seq = Nil | Cons of 'a * ('a * 'a) my_seq
let rec sizeS : 'a. 'a my_seq -> int = function | Nil -> 0 | Cons (_, my_seq) -> 1 + 2 * sizeS my_seq
type 'a my_seq = Nil | Cons of 'a * ('a * 'a) my_seq
let rec sizeS : 'a. 'a my_seq -> int = function | Nil -> 0 | Cons (_, my_seq) -> 1 + 2 * sizeS my_seq
type 'a my_seq = Nil | Cons of 'a * ('a * 'a) my_seq
let rec sizeS : 'a. 'a my_seq -> int = function | Nil -> 0 | Cons (_, my_seq) -> 1 + 2 * sizeS my_seq
type 'a my_seq = Nil | Cons of 'a * ('a * 'a) my_seq
let rec sizeS : 'a. 'a my_seq -> int = function | Nil -> 0 | Cons (_, my_seq) -> 1 + 2 * sizeS my_seq
type 'a my_seq = Nil | Cons of 'a * ('a * 'a) my_seq
let rec sizeS : 'a. 'a my_seq -> int = function | Nil -> 0 | Cons (_, my_seq) -> 1 + 2 * sizeS my_seq
OCaml 3.12.0 以降であれば、関数に直接型宣言書くだけでOK。OCaml 3.12.0 以降であれば、関数に直接型宣言書くだけでOK。OCaml 3.12.0 以降であれば、関数に直接型宣言書くだけでOK。OCaml 3.12.0 以降であれば、関数に直接型宣言書くだけでOK。OCaml 3.12.0 以降であれば、関数に直接型宣言書くだけでOK。
![Page 7: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/7.jpg)
HaskellだとHaskellだとHaskellだとHaskellだとHaskellだとdata MySeq a = MSNil | MSCons (a, MySeq (a,a))
sizeS :: MySeq a -> IntsizeS MSNil = 0sizeS (MSCons (_, ps)) = 1 + 2 * sizeS ps
data MySeq a = MSNil | MSCons (a, MySeq (a,a))
sizeS :: MySeq a -> IntsizeS MSNil = 0sizeS (MSCons (_, ps)) = 1 + 2 * sizeS ps
data MySeq a = MSNil | MSCons (a, MySeq (a,a))
sizeS :: MySeq a -> IntsizeS MSNil = 0sizeS (MSCons (_, ps)) = 1 + 2 * sizeS ps
data MySeq a = MSNil | MSCons (a, MySeq (a,a))
sizeS :: MySeq a -> IntsizeS MSNil = 0sizeS (MSCons (_, ps)) = 1 + 2 * sizeS ps
data MySeq a = MSNil | MSCons (a, MySeq (a,a))
sizeS :: MySeq a -> IntsizeS MSNil = 0sizeS (MSCons (_, ps)) = 1 + 2 * sizeS ps
こちらも型宣言書けば問題ない。こちらも型宣言書けば問題ない。こちらも型宣言書けば問題ない。こちらも型宣言書けば問題ない。こちらも型宣言書けば問題ない。
![Page 8: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/8.jpg)
再帰関数に型宣言付けるのがキモ再帰関数に型宣言付けるのがキモ再帰関数に型宣言付けるのがキモ再帰関数に型宣言付けるのがキモ再帰関数に型宣言付けるのがキモ
型宣言を付けないと、こんなエラーになってしまいます。型宣言を付けないと、こんなエラーになってしまいます。型宣言を付けないと、こんなエラーになってしまいます。型宣言を付けないと、こんなエラーになってしまいます。型宣言を付けないと、こんなエラーになってしまいます。MySeq.hs:7:40: Occurs check: cannot construct the infinite type: t0 = (t0, t0) Expected type: MySeq t0 Actual type: MySeq (t0, t0) In the first argument of `sizeS', namely `ps' In the second argument of `(*)', namely `sizeS ps'
MySeq.hs:7:40: Occurs check: cannot construct the infinite type: t0 = (t0, t0) Expected type: MySeq t0 Actual type: MySeq (t0, t0) In the first argument of `sizeS', namely `ps' In the second argument of `(*)', namely `sizeS ps'
MySeq.hs:7:40: Occurs check: cannot construct the infinite type: t0 = (t0, t0) Expected type: MySeq t0 Actual type: MySeq (t0, t0) In the first argument of `sizeS', namely `ps' In the second argument of `(*)', namely `sizeS ps'
MySeq.hs:7:40: Occurs check: cannot construct the infinite type: t0 = (t0, t0) Expected type: MySeq t0 Actual type: MySeq (t0, t0) In the first argument of `sizeS', namely `ps' In the second argument of `(*)', namely `sizeS ps'
MySeq.hs:7:40: Occurs check: cannot construct the infinite type: t0 = (t0, t0) Expected type: MySeq t0 Actual type: MySeq (t0, t0) In the first argument of `sizeS', namely `ps' In the second argument of `(*)', namely `sizeS ps'
型変数t0が何者なのか調べようとして、発散してしまうらしい。型変数t0が何者なのか調べようとして、発散してしまうらしい。型変数t0が何者なのか調べようとして、発散してしまうらしい。型変数t0が何者なのか調べようとして、発散してしまうらしい。型変数t0が何者なのか調べようとして、発散してしまうらしい。
![Page 9: PFDS 10.1.1 多相再帰](https://reader030.vdocuments.mx/reader030/viewer/2022013102/54b6c13a4a7959d7268b45a8/html5/thumbnails/9.jpg)
参考文献参考文献参考文献参考文献参考文献* recursive module で polymorphic recursion を書く (camlspotter) http://d.hatena.ne.jp/camlspotter/20090408/1239172620* 多相再帰 - λx.x K S K @ はてな http://d.hatena.ne.jp/KeisukeNakano/20060720/1153367670* polymorphic recursion の話 - Hatena::Diary::pi8027 http://d.hatena.ne.jp/pi8027/20101121/polymorphic_recursion* 今日のスライドで使ったコード例 https://github.com/master-q/readPurelyFunctionalDataStructures/tree/master/PolymorphicRecursion
* recursive module で polymorphic recursion を書く (camlspotter) http://d.hatena.ne.jp/camlspotter/20090408/1239172620* 多相再帰 - λx.x K S K @ はてな http://d.hatena.ne.jp/KeisukeNakano/20060720/1153367670* polymorphic recursion の話 - Hatena::Diary::pi8027 http://d.hatena.ne.jp/pi8027/20101121/polymorphic_recursion* 今日のスライドで使ったコード例 https://github.com/master-q/readPurelyFunctionalDataStructures/tree/master/PolymorphicRecursion
* recursive module で polymorphic recursion を書く (camlspotter) http://d.hatena.ne.jp/camlspotter/20090408/1239172620* 多相再帰 - λx.x K S K @ はてな http://d.hatena.ne.jp/KeisukeNakano/20060720/1153367670* polymorphic recursion の話 - Hatena::Diary::pi8027 http://d.hatena.ne.jp/pi8027/20101121/polymorphic_recursion* 今日のスライドで使ったコード例 https://github.com/master-q/readPurelyFunctionalDataStructures/tree/master/PolymorphicRecursion
* recursive module で polymorphic recursion を書く (camlspotter) http://d.hatena.ne.jp/camlspotter/20090408/1239172620* 多相再帰 - λx.x K S K @ はてな http://d.hatena.ne.jp/KeisukeNakano/20060720/1153367670* polymorphic recursion の話 - Hatena::Diary::pi8027 http://d.hatena.ne.jp/pi8027/20101121/polymorphic_recursion* 今日のスライドで使ったコード例 https://github.com/master-q/readPurelyFunctionalDataStructures/tree/master/PolymorphicRecursion
* recursive module で polymorphic recursion を書く (camlspotter) http://d.hatena.ne.jp/camlspotter/20090408/1239172620* 多相再帰 - λx.x K S K @ はてな http://d.hatena.ne.jp/KeisukeNakano/20060720/1153367670* polymorphic recursion の話 - Hatena::Diary::pi8027 http://d.hatena.ne.jp/pi8027/20101121/polymorphic_recursion* 今日のスライドで使ったコード例 https://github.com/master-q/readPurelyFunctionalDataStructures/tree/master/PolymorphicRecursion