SlideShare a Scribd company logo
Phantom Type in Scala	
 
ファントムタイプ社の社長にみんなでPhatom Typeを教える会



        2012.10.06 前田康行(@maeda_)
自己紹介	
 

•  前⽥田康⾏行行 (@maeda_ )


•  好きな⾔言語
  •  Scala
  •  Smalltalk


•  DyNagoya (Dynamic language + Nagoya)
  •  http://dynagoya.info
About Phatom Type	
 

A phantom type is a parametrised type whose
parameters do not all appear on the right-hand
side of its definition



- Haskell wiki より抜粋 -

http://www.haskell.org/haskellwiki/Phantom_type
幽霊型の例	
 
•  型パラメータTはcase classのフィールドに使われて
   いない
case class A[T](x : Int)

scala> A[String](3)
res0: A [String] = A(3)

scala> A [List[Char]](3)
res1: A [List[Char]] = A(3)

scala> res0 == res1
res2: Boolean = true

•  特にScalaの場合、Type Erasureにより実⾏行行時に型パ
   ラメータは消える
Phantom Typeは幽霊なのか?	
 

•  Phantom Type(幽霊型)は
 •  実⾏行行時ではなく、コンパイル時にのみ暗躍する。
 •  条件を満たさないと、コンパイルエラーにして実⾏行行
    できなくする呪いをかける
 •  コンパイルが通ると成仏していなくなる


•  これは幽霊ですね
Phatom Typeの実用例	
 1
            Type Safeな構文木	
 
    •  Expr[T]は評価結果がT型となることを表す
trait Expr[T]
case object True extends Expr[Boolean]
case object False extends Expr [Boolean]
case class Number(x: Int) extendsExpr [Int]
case class Plus(x1: Expr [Int], x2:Expr [Int]) extends Expr [Int]

scala> Plus(Plus(Number(3),Number(4)),Number(5))
res4: Plus = Plus(Plus(Number(3),Number(4)),Number(5))

scala> Plus(Plus(Number(3), Number(4)), True) // PlusにBooleanは渡せない
<console>:14: error: type mismatch;
 found : True.type
 required: Expr[Int]
          Plus(Plus(Number(3), Number(4)), True)
Phatom Typeの実用例	
 2
             状態を表す(定義)	
 
sealed trait State
class Empty private () extends State
class Ready private () extends State

class Dinner[Oeuvre <: State, MainDish <: State, Dessert <: State] (){
   def cookSalad = new Dinner[Ready, MainDish, Dessert]
   def cookSoup = new Dinner[Ready, MainDish, Dessert]
   def cookSteak = new Dinner[Oeuvre, Ready, Dessert]
   def cookCake = new Dinner[Oeuvre, MainDish, Ready]

  def serve() = println("Now you can eat!")
}
object Dinner{
  def start = new Dinner[Empty, Empty, Empty]
}
Phatom Typeの実用例	
 2
          状態を表す(実行例)	
 
scala> Dinner.start
res0: Dinner[Empty, Empty, Empty] = Dinner@4b401150


scala> Dinner.start.cookSalad.cookCake
res1: Dinner[Ready, Empty, Ready] = Dinner@6d9e4f58


scala> Dinner.start.cookSalad.cookCake.serve()
Now you can eat!


scala> Dinner.start.cookSalad.cookSteak.cookSoup.serve()
Now you can eat!
ただのタグじゃなくて、
コンパイルエラーにしたい
そこで
 Implicit Parameter
(暗黙のパラメータ)
      ですよ
implicit parameterの例	
 
// implicit parameter付きの関数の宣⾔言
scala> def func(implicit ev: Int) = m
// implicit parameterが⾒見見つからないのでエラー
scala> func
<console>:9: error: could not find implicit value for parameter
m: Int

// スコープ内にimplicitで宣⾔言した値があると、⾃自動的に渡される
scala> implicit val v = 3
scala> func // → 3

 •  スコープ内のimplicitで宣⾔言された値の中で、
    型が合う値をコンパイル時に探索する
多相的なimplicit parameter	
 
scala> def implicitly[T](implicit ev: T) = m

scala> implicit val v = 3
scala> implicitly[Int]         // → 3
scala> implicitly[String]      // →  コンパイルエラー


 •  implicitlyメソッドはPredefに標準で定義されている

 •  型パラメータで指定された型のimplicitに取得できる
    値を探索
もう少しお行儀よく	
 
class Tag[A]()
def func[A](implicit ev: Tag[A]) = "OK
implicit val intAllowed = new Tag[Int]


scala> func[Int]       // → OK
scala> func[String]     // →コンパイルエラー

 •  普通に使う型をimplicitで宣⾔言するのはよくない

 •  implicitで使⽤用するための型を⽤用意して、その型
    パラメータで特定の型を指定する⽅方がいい
型パラメータを2つにする	
 
class Tag[A, B] ()
def func[A, B](implicit ev: Tag[A, B]) = "OK"
implicit val intAllowed = new Tag[Int, Int]
implicit val stringAllowed = new Tag[String, String]

scala> func[Int, Int]    // OK
scala> func[Int, String] // コンパイルエラー

 •  個別に使⽤用可能な型の組み合わせをimplicitで宣
    ⾔言する
任意の2つの型が同じである
   ことを表現したい	
 
•  型パラメータを持った値は扱えない

   implicit val x[A] = new Tag[A, A]


•  メソッドなら型パラメータを持てる
 ○ implicit def f[A] = new Tag[A, A]
2つの型が同じ場合
         呼び出し可能な関数	
 
class Tag[A, B] ()
implicit def equalAllowed[A] = new Tag[A, A]
def func[A, B](implicit ev: Tag[A, B]) = "OK


scala> func[Int, Int]    // → OK
scala> func[Int, String] // → コンパイルエラー
インスタンス生成の無駄を省く	
 
class Tag[A, B] ()
val singletonTag = new Tag[Any, Any]
implicit def equalAllowed[A]: Tag[A, A] =
           singletonTag.asInstanceOf[Tag[A, A]]

def func[A, B](implicit ev: Tag[A, B]) = "OK"

 •  implicitで呼び出される度にインスタンス⽣生成するのは無駄

 •  implicitで渡される値は使われないので、型さえあえば、中
    ⾝身はなんでもいい

 •  nullでもOK
2つの型パラメータをとる型の
   シンタックスシュガー	
 
scala> class Op[A, B] ()

scala> val x: Op[Int, String] = new Op
x: Op[Int,String] = Op@ab612f8

scala> val x: Int Op String = new Op
x: Op[Int,String] = Op@165e6c89

•  中置記法の⽅方が型の演算⼦子っぽく⾒見見える
•  クラス名に記号も使える。記号の⽅方がより演算⼦子っぽい
Scala 2.10-M7の実装	
 
sealed abstract class =:=[From, To]
                  extends (From => To) with Serializable
private[this] final val singleton_=:= =
        new =:=[Any,Any] { def apply(x: Any): Any = x }
object =:= {
    implicit def tpEquals[A]: A =:= A =
      singleton_=:=.asInstanceOf[A =:= A]
}

•  From => To を継承しているため、型を変換する関数とし
   て使える
def func[A](x1: A)(implicit w: A =:= B ) = {
  val x2 = w(x1)             // x2はB型として使える
  ...
}

•  Serializableを継承している利⽤用は不明
generalized type constraints	
 
scala> implicitly[Int =:= Int]
res7: =:=[Int,Int] = <function1>


scala> implicitly[Int =:= String]
<console>:9: error: Cannot prove that Int =:= String.
         implicitly[Int =:= String]
                 ^


    •  異なる型を渡すとコンパイルエラー
Prove?	
 

これは、あの証明ですか?	
 



      ← あの証明です
証明は身近な存在	
 

•  カリー・ハワード同型対応
 •  型 ⇆ 命題
 •  プログラム ⇆ 証明


•  プログラムに型が付く ⇆ 命題が証明された



•  「A =:= B」型について、それを満たすimplicitをコ
   ンパイラが⾒見見つけて、型が付けば、「AがBであるこ
   と」が証明されている
定理証明支援器 Coq	
 

•  型の表現⼒力力がすごい
   例:迷路の経路が最短経路である型
   http://d.hatena.ne.jp/yoshihiro503/20100119



•  そんな型を満たすようなプログラムを書くのは⼤大
   変
  •  Coqは⼈人にやさしい形で⽀支援してくれる
一方、Scalaは	
 

•  型レベルλ計算
   http://apocalisp.wordpress.com/
   2010/06/08/type-level-programming-in-
   scala/
•  型レベル命題論理
   http://www.chuusai.com/2011/06/09/scala-
   union-types-curry-howard/


•  ⼀一応、がんばれば、、、
まとめ	
 

•  Phantom Type(幽霊型)はコンパイル時に暗躍

•  使いこなすには型レベルでいろいろやりたくなる

•  Scalaでは、implicit parameterを利⽤用して、コ
   ンパイル時にいろいろできる

•  Coqすごい
もっと型の力を知りたい人は	
 
•  ProofCafe(毎⽉月第4⼟土曜)
  •  名古屋でプログラムの証明について勉強する勉強会で
     す。現在はソフトウェアの基礎というドキュメントを
     読んでいます。コーヒーを飲みながら楽しく証明しま
     しょう。
     http://proofcafe.org/wiki/

•  TAPL-nagoya (毎⽉月第3⼟土曜)
  •  ScalaやF#やSML#などの静的型付け⾔言語の基礎に
     なっている型理論についての勉強会です。英語ですが、
     説明が丁寧で例が豊富な TAPL をみんなで読みます。
  •  http://proofcafe.org/tapl/
その他
<%< はなくなった
            (2.10から)	
 
 •  「A => B」でOK

scala> implicitly[ Int <%< Long ]
<console>:12: error: not found: type >%>
         implicitly[ Int <%< Long ]
                      ^


scala> implicitly[ Int => Long ]
res5: Int => Long = <function1>
<%<は、なぜなくなったのか	
 


•  SI-2781

•  type inference constraints should be
   carried along during search for chained
   implicits

•  https://issues.scala-lang.org/browse/
   SI-2781
演習問題	
 1	
 
•  9ページの例をコンパイルエラーを出すようにする

scala> Dinner.start.cookSalad.cookCake.serve()
<console>:8: error: Cannot prove that Dinner.Empty =:=
Dinner.Ready.
         Dinner.start.cookSalad.cookCake.serve()
                                  ^
scala> Dinner.start.cookSalad.cookCake.cookSalad
<console>:8: error: Cannot prove that Dinner.Ready =:=
Dinner.Empty.
         Dinner.start.cookSalad.cookCake.cookSalad
                               ^

scala> Dinner.start.cookSalad.cookCake.cookSteak.serve()
Now you can eat!
演習問題 2	
 
•  AがBの⼦子クラスであるかをチェックする型を考えてみる

scala> trait A
scala> trait B with A

scala> implicitly[ B <:< A ]
res9: <:<[B,A] = <function1>

scala> implicitly[ A <:< B ]
<console>:14: error: Cannot prove that A <:< B.
         implicitly[ A <:< B ]
参考文献	
 
•  Type classes as objects and implicitsBruno
   C.d.S. Oliveira, Adriaan Moors,
   Martin Odersky
   OOPSLA ʻ‘10 Proceedings of the ACM
   international conference on Object oriented
   programming systems languages and
   applications, 2010

  この論⽂文の「6.6 Encoding generalized
  constraints」に>:>の話がある(少しだけど)

More Related Content

PDF
Essential Scala 第4章 トレイトによるデータモデリング
PDF
Kotlinミニアンチパターン
PDF
キメるClojure
PDF
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)
PDF
今どきのアーキテクチャ設計戦略 - QCon Tokyo 2016
PDF
golang profiling の基礎
PDF
並行処理初心者のためのAkka入門
PDF
できる!並列・並行プログラミング
Essential Scala 第4章 トレイトによるデータモデリング
Kotlinミニアンチパターン
キメるClojure
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)
今どきのアーキテクチャ設計戦略 - QCon Tokyo 2016
golang profiling の基礎
並行処理初心者のためのAkka入門
できる!並列・並行プログラミング

What's hot (20)

PDF
【BS13】チーム開発がこんなにも快適に!コーディングもデバッグも GitHub 上で。 GitHub Codespaces で叶えられるシームレスな開発
PDF
機械学習システムのアーキテクチャアラカルト
PDF
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
PDF
イミュータブルデータモデルの極意
PDF
エンジニアのための経営学
KEY
やはりお前らのMVCは間違っている
PDF
Domain Modeling Made Functional (DevTernity 2022)
PDF
モジュールの凝集度・結合度・インタフェース
PDF
traitを使って楽したい話
PPTX
マイクロサービスにおける 非同期アーキテクチャ
PPT
Java Tut1
PPTX
世界一わかりやすいClean Architecture
PDF
Rx入門
PDF
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
PPT
メタプログラミングって何だろう
PDF
徳丸本ができるまで
PDF
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
PDF
Apache Airflow入門 (マーケティングデータ分析基盤技術勉強会)
PDF
理解して使うRNA Velocity解析ツール-最近のツール編
PPTX
PHPのテスト名を日本語にした話
【BS13】チーム開発がこんなにも快適に!コーディングもデバッグも GitHub 上で。 GitHub Codespaces で叶えられるシームレスな開発
機械学習システムのアーキテクチャアラカルト
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
イミュータブルデータモデルの極意
エンジニアのための経営学
やはりお前らのMVCは間違っている
Domain Modeling Made Functional (DevTernity 2022)
モジュールの凝集度・結合度・インタフェース
traitを使って楽したい話
マイクロサービスにおける 非同期アーキテクチャ
Java Tut1
世界一わかりやすいClean Architecture
Rx入門
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
メタプログラミングって何だろう
徳丸本ができるまで
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
Apache Airflow入門 (マーケティングデータ分析基盤技術勉強会)
理解して使うRNA Velocity解析ツール-最近のツール編
PHPのテスト名を日本語にした話
Ad

Viewers also liked (20)

PDF
Monocleとかいうのがありまして
PDF
はじめて Phantom と遭遇して、闇雲に闘いを挑んでみた話 #kbkz_tech
PDF
MySQL 5.7 InnoDB 日本語全文検索(その2)
PDF
Impression of realm java
PDF
LTE Air Interface
PDF
楕円曲線入門 トーラスと楕円曲線のつながり
PDF
Enduring CSS
PDF
Vue.js with Go
PDF
Rの高速化
PDF
PHPでスマホアプリにプッシュ通知する
PDF
Kubernetes in 30 minutes (2017/03/10)
PDF
Neo4jで始めるグラフDB入門 - LT Thursday
PDF
実務者のためのかんたんScalaz
PPTX
フロントエンドで GraphQLを使った所感
PPTX
SparkとJupyterNotebookを使った分析処理 [Html5 conference]
PDF
Performance optimisation with GraphQL
PDF
リテラルと型の続きの話 #__swift__
PPTX
Apache Sparkを使った感情極性分析
PPTX
Prefer Cloud Platform - ビジョン、アーキテクチャ
PPTX
PostgreSQL画像データ収集・格納
Monocleとかいうのがありまして
はじめて Phantom と遭遇して、闇雲に闘いを挑んでみた話 #kbkz_tech
MySQL 5.7 InnoDB 日本語全文検索(その2)
Impression of realm java
LTE Air Interface
楕円曲線入門 トーラスと楕円曲線のつながり
Enduring CSS
Vue.js with Go
Rの高速化
PHPでスマホアプリにプッシュ通知する
Kubernetes in 30 minutes (2017/03/10)
Neo4jで始めるグラフDB入門 - LT Thursday
実務者のためのかんたんScalaz
フロントエンドで GraphQLを使った所感
SparkとJupyterNotebookを使った分析処理 [Html5 conference]
Performance optimisation with GraphQL
リテラルと型の続きの話 #__swift__
Apache Sparkを使った感情極性分析
Prefer Cloud Platform - ビジョン、アーキテクチャ
PostgreSQL画像データ収集・格納
Ad

Similar to Phantom Type in Scala (20)

PDF
Scalaで型クラス入門
PDF
Implicit Explicit Scala
PDF
What Dotty fixes @ Scala関西サミット
PDF
Scala の関数型プログラミングを支える技術
PDF
プログラミング言語Scala
PDF
Thinking in Cats
KEY
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
PDF
From Scala/Clojure to Kotlin
PDF
型クラス
PPTX
ゼロから始めるScala文法 (再)
PDF
Let's Simulate a Quantum Computer with Pretty Scala
PDF
こわくない型クラス
ODP
これから Haskell を書くにあたって
PDF
Haskell勉強会2 in ie
PDF
Python と型ヒント (Type Hints)
PDF
すごいHaskell読書会
PDF
Essential Scala 第5章 シーケンス処理
PDF
PDF
BOF1-Scala02.pdf
PDF
BOF1-Scala02.pdf
Scalaで型クラス入門
Implicit Explicit Scala
What Dotty fixes @ Scala関西サミット
Scala の関数型プログラミングを支える技術
プログラミング言語Scala
Thinking in Cats
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
From Scala/Clojure to Kotlin
型クラス
ゼロから始めるScala文法 (再)
Let's Simulate a Quantum Computer with Pretty Scala
こわくない型クラス
これから Haskell を書くにあたって
Haskell勉強会2 in ie
Python と型ヒント (Type Hints)
すごいHaskell読書会
Essential Scala 第5章 シーケンス処理
BOF1-Scala02.pdf
BOF1-Scala02.pdf

Phantom Type in Scala

  • 1. Phantom Type in Scala ファントムタイプ社の社長にみんなでPhatom Typeを教える会 2012.10.06 前田康行(@maeda_)
  • 2. 自己紹介 •  前⽥田康⾏行行 (@maeda_ ) •  好きな⾔言語 •  Scala •  Smalltalk •  DyNagoya (Dynamic language + Nagoya) •  http://dynagoya.info
  • 3. About Phatom Type A phantom type is a parametrised type whose parameters do not all appear on the right-hand side of its definition - Haskell wiki より抜粋 - http://www.haskell.org/haskellwiki/Phantom_type
  • 4. 幽霊型の例 •  型パラメータTはcase classのフィールドに使われて いない case class A[T](x : Int) scala> A[String](3) res0: A [String] = A(3) scala> A [List[Char]](3) res1: A [List[Char]] = A(3) scala> res0 == res1 res2: Boolean = true •  特にScalaの場合、Type Erasureにより実⾏行行時に型パ ラメータは消える
  • 5. Phantom Typeは幽霊なのか? •  Phantom Type(幽霊型)は •  実⾏行行時ではなく、コンパイル時にのみ暗躍する。 •  条件を満たさないと、コンパイルエラーにして実⾏行行 できなくする呪いをかける •  コンパイルが通ると成仏していなくなる •  これは幽霊ですね
  • 6. Phatom Typeの実用例 1 Type Safeな構文木 •  Expr[T]は評価結果がT型となることを表す trait Expr[T] case object True extends Expr[Boolean] case object False extends Expr [Boolean] case class Number(x: Int) extendsExpr [Int] case class Plus(x1: Expr [Int], x2:Expr [Int]) extends Expr [Int] scala> Plus(Plus(Number(3),Number(4)),Number(5)) res4: Plus = Plus(Plus(Number(3),Number(4)),Number(5)) scala> Plus(Plus(Number(3), Number(4)), True) // PlusにBooleanは渡せない <console>:14: error: type mismatch; found : True.type required: Expr[Int] Plus(Plus(Number(3), Number(4)), True)
  • 7. Phatom Typeの実用例 2 状態を表す(定義) sealed trait State class Empty private () extends State class Ready private () extends State class Dinner[Oeuvre <: State, MainDish <: State, Dessert <: State] (){ def cookSalad = new Dinner[Ready, MainDish, Dessert] def cookSoup = new Dinner[Ready, MainDish, Dessert] def cookSteak = new Dinner[Oeuvre, Ready, Dessert] def cookCake = new Dinner[Oeuvre, MainDish, Ready] def serve() = println("Now you can eat!") } object Dinner{ def start = new Dinner[Empty, Empty, Empty] }
  • 8. Phatom Typeの実用例 2 状態を表す(実行例) scala> Dinner.start res0: Dinner[Empty, Empty, Empty] = Dinner@4b401150 scala> Dinner.start.cookSalad.cookCake res1: Dinner[Ready, Empty, Ready] = Dinner@6d9e4f58 scala> Dinner.start.cookSalad.cookCake.serve() Now you can eat! scala> Dinner.start.cookSalad.cookSteak.cookSoup.serve() Now you can eat!
  • 11. implicit parameterの例 // implicit parameter付きの関数の宣⾔言 scala> def func(implicit ev: Int) = m // implicit parameterが⾒見見つからないのでエラー scala> func <console>:9: error: could not find implicit value for parameter m: Int // スコープ内にimplicitで宣⾔言した値があると、⾃自動的に渡される scala> implicit val v = 3 scala> func // → 3 •  スコープ内のimplicitで宣⾔言された値の中で、 型が合う値をコンパイル時に探索する
  • 12. 多相的なimplicit parameter scala> def implicitly[T](implicit ev: T) = m scala> implicit val v = 3 scala> implicitly[Int]         // → 3 scala> implicitly[String]      // →  コンパイルエラー •  implicitlyメソッドはPredefに標準で定義されている •  型パラメータで指定された型のimplicitに取得できる 値を探索
  • 13. もう少しお行儀よく class Tag[A]() def func[A](implicit ev: Tag[A]) = "OK implicit val intAllowed = new Tag[Int] scala> func[Int] // → OK scala> func[String] // →コンパイルエラー •  普通に使う型をimplicitで宣⾔言するのはよくない •  implicitで使⽤用するための型を⽤用意して、その型 パラメータで特定の型を指定する⽅方がいい
  • 14. 型パラメータを2つにする class Tag[A, B] () def func[A, B](implicit ev: Tag[A, B]) = "OK" implicit val intAllowed = new Tag[Int, Int] implicit val stringAllowed = new Tag[String, String] scala> func[Int, Int] // OK scala> func[Int, String] // コンパイルエラー •  個別に使⽤用可能な型の組み合わせをimplicitで宣 ⾔言する
  • 15. 任意の2つの型が同じである ことを表現したい •  型パラメータを持った値は扱えない implicit val x[A] = new Tag[A, A] •  メソッドなら型パラメータを持てる ○ implicit def f[A] = new Tag[A, A]
  • 16. 2つの型が同じ場合 呼び出し可能な関数 class Tag[A, B] () implicit def equalAllowed[A] = new Tag[A, A] def func[A, B](implicit ev: Tag[A, B]) = "OK scala> func[Int, Int] // → OK scala> func[Int, String] // → コンパイルエラー
  • 17. インスタンス生成の無駄を省く class Tag[A, B] () val singletonTag = new Tag[Any, Any] implicit def equalAllowed[A]: Tag[A, A] = singletonTag.asInstanceOf[Tag[A, A]] def func[A, B](implicit ev: Tag[A, B]) = "OK" •  implicitで呼び出される度にインスタンス⽣生成するのは無駄 •  implicitで渡される値は使われないので、型さえあえば、中 ⾝身はなんでもいい •  nullでもOK
  • 18. 2つの型パラメータをとる型の シンタックスシュガー scala> class Op[A, B] () scala> val x: Op[Int, String] = new Op x: Op[Int,String] = Op@ab612f8 scala> val x: Int Op String = new Op x: Op[Int,String] = Op@165e6c89 •  中置記法の⽅方が型の演算⼦子っぽく⾒見見える •  クラス名に記号も使える。記号の⽅方がより演算⼦子っぽい
  • 19. Scala 2.10-M7の実装 sealed abstract class =:=[From, To]                   extends (From => To) with Serializable private[this] final val singleton_=:= = new =:=[Any,Any] { def apply(x: Any): Any = x } object =:= { implicit def tpEquals[A]: A =:= A = singleton_=:=.asInstanceOf[A =:= A] } •  From => To を継承しているため、型を変換する関数とし て使える def func[A](x1: A)(implicit w: A =:= B ) = { val x2 = w(x1) // x2はB型として使える ... } •  Serializableを継承している利⽤用は不明
  • 20. generalized type constraints scala> implicitly[Int =:= Int] res7: =:=[Int,Int] = <function1> scala> implicitly[Int =:= String] <console>:9: error: Cannot prove that Int =:= String. implicitly[Int =:= String] ^ •  異なる型を渡すとコンパイルエラー
  • 22. 証明は身近な存在 •  カリー・ハワード同型対応 •  型 ⇆ 命題 •  プログラム ⇆ 証明 •  プログラムに型が付く ⇆ 命題が証明された •  「A =:= B」型について、それを満たすimplicitをコ ンパイラが⾒見見つけて、型が付けば、「AがBであるこ と」が証明されている
  • 23. 定理証明支援器 Coq •  型の表現⼒力力がすごい 例:迷路の経路が最短経路である型 http://d.hatena.ne.jp/yoshihiro503/20100119 •  そんな型を満たすようなプログラムを書くのは⼤大 変 •  Coqは⼈人にやさしい形で⽀支援してくれる
  • 24. 一方、Scalaは •  型レベルλ計算 http://apocalisp.wordpress.com/ 2010/06/08/type-level-programming-in- scala/ •  型レベル命題論理 http://www.chuusai.com/2011/06/09/scala- union-types-curry-howard/ •  ⼀一応、がんばれば、、、
  • 25. まとめ •  Phantom Type(幽霊型)はコンパイル時に暗躍 •  使いこなすには型レベルでいろいろやりたくなる •  Scalaでは、implicit parameterを利⽤用して、コ ンパイル時にいろいろできる •  Coqすごい
  • 26. もっと型の力を知りたい人は •  ProofCafe(毎⽉月第4⼟土曜) •  名古屋でプログラムの証明について勉強する勉強会で す。現在はソフトウェアの基礎というドキュメントを 読んでいます。コーヒーを飲みながら楽しく証明しま しょう。 http://proofcafe.org/wiki/ •  TAPL-nagoya (毎⽉月第3⼟土曜) •  ScalaやF#やSML#などの静的型付け⾔言語の基礎に なっている型理論についての勉強会です。英語ですが、 説明が丁寧で例が豊富な TAPL をみんなで読みます。 •  http://proofcafe.org/tapl/
  • 28. <%< はなくなった (2.10から) •  「A => B」でOK scala> implicitly[ Int <%< Long ] <console>:12: error: not found: type >%> implicitly[ Int <%< Long ] ^ scala> implicitly[ Int => Long ] res5: Int => Long = <function1>
  • 29. <%<は、なぜなくなったのか •  SI-2781 •  type inference constraints should be carried along during search for chained implicits •  https://issues.scala-lang.org/browse/ SI-2781
  • 30. 演習問題 1 •  9ページの例をコンパイルエラーを出すようにする scala> Dinner.start.cookSalad.cookCake.serve() <console>:8: error: Cannot prove that Dinner.Empty =:= Dinner.Ready. Dinner.start.cookSalad.cookCake.serve() ^ scala> Dinner.start.cookSalad.cookCake.cookSalad <console>:8: error: Cannot prove that Dinner.Ready =:= Dinner.Empty. Dinner.start.cookSalad.cookCake.cookSalad ^ scala> Dinner.start.cookSalad.cookCake.cookSteak.serve() Now you can eat!
  • 31. 演習問題 2 •  AがBの⼦子クラスであるかをチェックする型を考えてみる scala> trait A scala> trait B with A scala> implicitly[ B <:< A ] res9: <:<[B,A] = <function1> scala> implicitly[ A <:< B ] <console>:14: error: Cannot prove that A <:< B. implicitly[ A <:< B ]
  • 32. 参考文献 •  Type classes as objects and implicitsBruno C.d.S. Oliveira, Adriaan Moors, Martin Odersky OOPSLA ʻ‘10 Proceedings of the ACM international conference on Object oriented programming systems languages and applications, 2010 この論⽂文の「6.6 Encoding generalized constraints」に>:>の話がある(少しだけど)