Share
Embed
計算ファースト vs. 型ファースト / Computation First vs. Type First
詳しい説明はこちらにあります:
https://tarao.hatenablog.com/entry/type-first
INA Lintaro
November 28, 2019
Transcript
33 slides
-
ܕ͕ͳ͍ͱ let apply2 = (f, n) => f(f(n)) apply2(1, 3)
Uncaught TypeError: f is not a function let omega = (x) => x(x) omega(omega) Uncaught RangeError: Maximum call stack size ex- ceeded -
ॻ͍ͯΑ͍ࣜΛ੍ݶ͢Δ ▶ ܕ͚نଇʹ߹கͨ͠ͷͷΈڐ͢ ▶ ྫ: ୯७ܕϥϜμܭࢉ (STLC) [Church 1940] x
: T ∈ Γ Γ ⊢ x : T (Var) Γ, x : ⌊S⌋ ⊢ m : T Γ ⊢ ((x:S) => m) : ⌊S⌋ → T (Abs) Γ ⊢ m : S → T Γ ⊢ n : S Γ ⊢ m(n) : T (App) ⌊(x:S) => T⌋ = ⌊S⌋ → ⌊T⌋ (otherwise) ⌊T⌋ = T ڐ͞ΕΔྫ: <A>(f: (a:A) => A) => (n: A) => f(f(n)) f : A → A ∈ {f : A → A, n : A} f : A → A, n : A ⊢ f : A → A f : A → A ∈ {f : A → A, n : A} f : A → A, n : A ⊢ f : A → A n : A ∈ {f : A → A, n : A} f : A → A, n : A ⊢ n : A f : A → A, n : A ⊢ f(n) : A (App) f : A → A, n : A ⊢ f(f(n)) : A (App) f : A → A ⊢ ((n: A) => f(f(n))) : A → A (Abs) ⊢ ((f: (a:A) => A) => (n: A) => f(f(n))) : (A → A) → A → A (Abs) -
ॻ͍ͯΑ͍ࣜΛ੍ݶ͢Δ ▶ ܕ͚نଇʹ߹கͨ͠ͷͷΈڐ͢ ▶ ྫ: ୯७ܕϥϜμܭࢉ (STLC) [Church 1940] x
: T ∈ Γ Γ ⊢ x : T (Var) Γ, x : ⌊S⌋ ⊢ m : T Γ ⊢ ((x:S) => m) : ⌊S⌋ → T (Abs) Γ ⊢ m : S → T Γ ⊢ n : S Γ ⊢ m(n) : T (App) ⌊(x:S) => T⌋ = ⌊S⌋ → ⌊T⌋ (otherwise) ⌊T⌋ = T ڐ͞Εͳ͍ྫ: <A, B>(x: (a:A) => B) => x(x) x : A → B ∈ {x : A → B} x : A → B ⊢ x : A → B (Var) x : A ̸∈ {x : A → B} x : A → B ⊢ x : A (Var) x : A → B ⊢ x(x) : B (App) ⊢ ((x: (a:A) => B) => x(x)) : (A → B) → B (Abs) -
ॻ͍ͯΑ͍ࣜΛ੍ݶ͢Δ let apply2 = <A>(f: (a: A) => A, n:
A) => f(f(n)) apply2(1, 3) Argument of type ’1’ is not assignable to parame- ter of type ’(a: 3) => 3’ apply2((n) => n*n, 3) // OK let omega = <A, B>(x: (a: A) => B) => x(x) Argument of type ’(a: A) => B’ is not assignable to pa- rameter of type ’A’ -
STLCͷੑ࣭ ܕͷ͍ͭͨࣜ ▶ ࣮ߦͨ݁͠Ռͷಉ͡ܕʹͳΔ ▶ ࠷ऴ݁Ռ͚ͩͰͳ࣮͘ߦ్தಉ༷ ▶ ओ෦؆ఆཧ (subject reduction)
ͱݴ͏ ▶ ࣮ߦͨ͠Βඞͣఀࢭ͢Δ (ඞͣ݁Ռͷ͕ಘΒΕΔ) ▶ ධՁઓུʹΑΒͳ͍ ▶ ڧਖ਼نԽੑ (strong normalization) ͱݴ͏ -
STLCͷݶք ▶ νϡʔϦϯάશͰͳ͍ (࠶ؼؔॻ͚ͳ͍) ▶ Ұݟ͢Δͱͳ͍ͷʹॻ͚ͳ͍͕ࣜ͋Δ ܕͳ͠ let apply2 =
(f, n) => f(f(n)) apply2((n) => [n], 3) => [[3]] ܕ͖ͭ let apply2 = <A>(f: (a: A) => A, n: A) => f(f(n)) apply2((n) => [n], 3) Type ’number[]’ is not assignable to type ’number’ -
(ऄ) ͦͦܕͱ ܕͱ ▶ σʔλͷϝϞϦϨΠΞτͷҧ͍Ͱͳ͍ ▶ ͷͷू·ΓΛ۠ผ͍ͨ֓͠೦Ͱ͚ͨͷ ܕͷىݯ [Kamareddine et
al. 2002] ▶ ݹ͘ϢʔΫϦου ▶ ʮʯͱʮઢʯΛ۠ผ͍ͯͨ͠ ▶ Theory of types [Russell 1908] ▶ ϥοηϧͷύϥυοΫεͷճආͷͨΊ ▶ ୯७ܕϥϜμܭࢉ [Church 1940] -
(ऄ) ͳͥSTLC࠶ؼͳ͠? ▶ ࣌·ͩίϯϐϡʔλͳ͔ͬͨ ▶ ͱͱ໋ؔ (ཧࣜΛͱΔؔ) Λఆ ▶ ϥοηϧͷύϥυοΫεͷճආ
▶ ΛͬͱఆࣜԽͨ͠ͷ ▶ ७ਮʹཧ্ֶͷٞͩͬͨ -
ܕ͋Δछͷ༷ ྫ (Scala) BookmarkRepository.find: BookmarkId => Option[BookmarkEntity] // - ϒοΫϚʔΫ
ID ͕͋ΔͳΒ, // - ϒοΫϚʔΫͷΤϯςΟςΟ͕͋ΕಘΒΕΔ Seq.sortBy: Seq[A] => (A => B) => Ordering[B] => Seq[A] // - A ͷྻ͕͋Γ, // - A Λ B ʹมͰ͖, // - B ͷॱং͕نఆ͞Ε͍ͯΕ, // - (B ͰιʔτࡁΈͷ)A ͷྻ͕ಘΒΕΔ Either.fold: Either[A, B] => (A => C) => (B => C) => C // - A ·ͨ B ͲͪΒ͔ͷΠϯελϯε͕͋Γ, // - A ͔Β C ͷมͱ, B ͔Β C ͷม͕͋Ε, // - ৗʹ C ͷΠϯελϯε͕ಘΒΕΔ -
ܕ͋Δछͷ༷ ܕͷಡΈํ ▶ ܕAʮAͷΠϯελϯε͕͋ΔʯΛදͯͦ͠͏ ▶ =>ʮͳΒʯΛදͯͦ͠͏ → ࣮ࡍͦ͏ ܕཧࣜ, ࣮ূ໌
▶ ܕ = ༷ (ཧࣜͰද໋ͨ͠) ▶ ܕͷ͍ͭͨࣜ = ༷͕ຬͨͤΔ͜ͱͷূ໌ ▶ ࣜʹܕ͕ͭ͘ ⇔ ༷Λຬ࣮͕ͨ͢ଘࡏ͢Δ -
ܕ͋Δछͷ༷ ܕͷಡΈํ ▶ ܕAʮAͷΠϯελϯε͕͋ΔʯΛදͯͦ͠͏ ▶ =>ʮͳΒʯΛදͯͦ͠͏ → ࣮ࡍͦ͏ ܕཧࣜ, ࣮ূ໌
▶ ܕ = ༷ (ཧࣜͰද໋ͨ͠) ▶ ܕͷ͍ͭͨࣜ = ༷͕ຬͨͤΔ͜ͱͷূ໌ ▶ ࣜʹܕ͕ͭ͘ ⇔ ༷Λຬ࣮͕ͨ͢ଘࡏ͢Δ Curry-HowardಉܕରԠ -
Curry-HowardಉܕରԠ STLC + ੵܕ (λϓϧ) + ܕͷܕ͚نଇ Γ, x :
φ ⊢ x : φ (Ax) Γ ⊢ m : ⊥ Γ ⊢ m : φ (⊥E) Γ, x : ⌊φ⌋ ⊢ m : ψ Γ ⊢ ((x:φ) => m) : ⌊φ⌋ → ψ (→I) Γ ⊢ m : φ → ψ Γ ⊢ n : φ Γ ⊢ m(n) : ψ (→E) Γ ⊢ m : φ Γ ⊢ n : ψ Γ ⊢ [m, n] : φ ∧ ψ (∧I) Γ ⊢ m : φ ∧ ψ Γ ⊢ m[0] : φ (∧E) Γ ⊢ m : φ ∧ ψ Γ ⊢ m[1] : ψ Γ ⊢ m : φ kind distinct in φ, ψ Γ ⊢ m : φ ∨ ψ (∨I) Γ ⊢ m : ψ kind distinct in φ, ψ Γ ⊢ m : φ ∨ ψ Γ ⊢ m : φ ∨ ψ Γ ⊢ n1 : φ → ϑ Γ ⊢ n2 : ψ → ϑ kind : Ki in φ, ψ Γ ⊢ switch (m.kind) { case Ki: return ni(m); ... } : ϑ (∨E) -
Curry-HowardಉܕରԠ ؍ओ໋ٛཧ (Gentzen ͷ NJ) Γ, x : φ ⊢
x : φ (Ax) Γ ⊢ m : ⊥ Γ ⊢ m : φ (⊥E) Γ, x : ⌊φ⌋ ⊢ m : ψ Γ ⊢ ((x:φ) => m) : ⌊φ⌋ → ψ (→I) Γ ⊢ m : φ → ψ Γ ⊢ n : φ Γ ⊢ m(n) : ψ (→E) Γ ⊢ m : φ Γ ⊢ n : ψ Γ ⊢ [m, n] : φ ∧ ψ (∧I) Γ ⊢ m : φ ∧ ψ Γ ⊢ m[0] : φ (∧E) Γ ⊢ m : φ ∧ ψ Γ ⊢ m[1] : ψ Γ ⊢ m : φ kind distinct in φ, ψ Γ ⊢ m : φ ∨ ψ (∨I) Γ ⊢ m : ψ kind distinct in φ, ψ Γ ⊢ m : φ ∨ ψ Γ ⊢ m : φ ∨ ψ Γ ⊢ n1 : φ → ϑ Γ ⊢ n2 : ψ → ϑ kind : Ki in φ, ψ Γ ⊢ switch (m.kind) { case Ki: return ni(m); ... } : ϑ (∨E) -
(ऄ) ຊʹ໋͕ઌ? ࣮ࡍʹূ໌Λॻ͍͍ͯΔͱ͖ ▶ ิΛॻ͘ͱ͖ޙ͔Β໋Λม͑Δ͜ͱ ▶ ͍͟͏ͱ͖ʹ͍উखͷѱ͞ʹؾͮ͘ ▶ ͏·͘ূ໌Ͱ͖ͳ͍ͷͰϓϥϯ B
ʹม͑Δ ▶ ͱ͍͍͖͑ͳΓূ໌Λॻ͘͜ͱͳͦ͞͏ ϓϩάϥϜΛॻ͘ͱ͖Ͳ͏ͨ͠ΒΑ͍? ▶ ϓϥΠϕʔτϝιου͖ʹͨ͠ΒΑ͍ ▶ ʮͳʹ͕Γཱ͔ͭͣ?ʯ৺͕͚͍ͨ -
ܕʮ͋Δछʯͷ༷ ܕͷදݱྗ͕ߴ͍ͱخ͍͠ ▶ ༷ͷදݱྗܕͷදݱྗʹґଘ ܕͷදݱྗ͕ߴ͗͢ΔͱࠔΔ ▶ Γ͗͢Δͱܕݕ͕ܾࠪఆෆೳʹͳΔ ▶ ܕਪ͕શͰͳ͘ͳΓ͕ͪ ▶
ϓϩάϥϜͰͳ͍͘͠ূ໌Λॻ͘͜ͱʹ ▶ Coq ͳͲ ▶ ূ໌Λॻ͍͔ͯͦ͜ΒϓϩάϥϜΛநग़ -
දݱྗͷߴ͍ܕ ཧମܥ ܭࢉମܥݴޠ ݹయཧ STLC + ܧଓ ೋ֊؍ओ໋ٛཧ System F
࣌૬ཧ MetaOCaml ઢܗཧ (ΞϑΟϯཧ) Rust -
͜͜·Ͱͷ·ͱΊ ▶ ࣜʹܕ͕ͭ͘ = ༷Λຬ࣮͕ͨ͢Ͱ͖ͨ ▶ ܕ = ༷ ▶
࣮ = ༷ͷ࣮ݱΛূ໌ ▶ ;ͭ͏༷͔Βઌʹߟ͑Δ ▶ ܕͷදݱྗΛߴΊΔͱࡉ͔͍༷ΛදݱͰ͖Δ ▶ දݱྗͷߴ͍ཧମܥ͋Δ (Ή͔͍ͣ͠) ▶ ଞʹͷ͔ͨ͋͠Δ (͜ͷ͋ͱհ) -
Scalaͷimplicit ྫ val l1: List[(Int, String)] = List(1 -> "foo",
2 -> "bar") val m1 = l1.toMap // m1: Map[Int, String] val l2: List[Int] = List(1, 2, 3) val m2 = l2.toMap // ίϯύΠϧΤϥʔ Ͳ͏ͬͯఆٛ͢Δ?? class List[A] { def toMap: Map[???] -
Scalaͷimplicit ྫ val l1: List[(Int, String)] = List(1 -> "foo",
2 -> "bar") val m1 = l1.toMap // m1: Map[Int, String] val l2: List[Int] = List(1, 2, 3) val m2 = l2.toMap // ίϯύΠϧΤϥʔ Ͳ͏ͬͯఆٛ͢Δ?? class List[A] { def toMap[K, V](implicit ev: A <:< (K, V) // Ճͷূ໌Λཁٻ ): Map[K, V] -
εϚʔτίϯετϥΫλ ྫ: ϦετΛඇۭʹݶఆ͍ͨ͠ val l1 = List(1, 2, 3) l1.head
// => 1 val l2 = List() l2.head // ࣮ߦ࣌Τϥʔ class Nel[A] private (val v: List[A]) object Nel { def apply[A](v: A*): Option[Nel[A]] = if (v.nonEmpty) Some(new Nel(v)) else None } val nel1 = Nel(1, 2, 3) nel1.map(_.v.head) // => Some(1) val nel2 = Nel() nel2.map(_.v.head) // => None -
ɹ ;Δ͍ ᝲ ɹܕ (refinement type) ྫ: ϦετͷඇۭੑΛอ͍ͪͨ val Some(nel1)
= Nel(1, 2, 3) nel1.v.map(n => n * n) // => List(1, 4, 9): List[Int] val Some(nel2) = RefinedNel(1, 2, 3) nel2.map(n => n * n) // => List(1, 4, 9): RefinedNel[Int] nel2.flatMap(n => List()) // => List(): List[Int] ▶ ަࠩܕ (intersection type) Ͱ࣮ݱ [Pfenning et al. 1991] ▶ Haskell Scala Ͱ Refined ͱ͍͏ϥΠϒϥϦ -
ߴΧΠϯυܕ ྫ trait Hoge[F[_]] ▶ ܕίϯετϥΫλΛҾʹऔΕΔ ▶ ͋Δͱݍతͳ֓೦ΛૉʹදݱͰ͖Δ ▶ αϙʔτͯ͠Δݴޠଟ͘ͳ͍
▶ Haskell, Scala, C++, Rust ͋ͨΓ? ▶ ͬͯ͏Ε͍͠ྫάά͍ͬͯͩ͘͞