View Bound/Context Bound

Scalaの「View Bound」と「Context Bound」について、そんなに解説がないわりに頻出するので、簡単な例をかいてみました。

Scala@東北とかでも結構当たり前のように登場する言葉・文法で、いまさら聞けない系の話題になってる感もある(全然そんなことないのですが)ので、参加者の中で耳にすると心が折れてしまう方がいれば参考にしてみてください。

View BoundContext Bound はいずれも、

「頻出する暗黙(implicit)変換・パラメータの利用方法」の
シンタックスシュガー


です。なので、理論的にステージが高い代物ではないので、REPLなどで動かして確認すればすぐ理解できると思います。

まずは、implicitのおさらいから

//implicitパラメータとは。。

implicit val a:Int = 1
implicit val s:String = "a"

def some(implicit v:Int) : Int = v
some // => 1

def some[Int](implicit v:Int) : Int = v
def some[String](implicit v:String) : String = v
some[Int] // => 1
some[String] // => "a"

//implicit パラメータに関数を入れる。

implicit def intBigger(a:Int,b:Int):Int = Math.max(a,b)
implicit def strBigger(a:String,b:String):String = if( a.compareTo(b) > 0 ) a else b

//普通に呼び出せば使えるが、

intBigger(1,2)
strBigger("a","b")

//これらをジェネリクスを使って抽象化すると、

def chooseBigger[T](a:T,b:T)(implicit func:(T,T)=>T) : T = func(a,b)

//(T,T)=>T 型の関数funcを探して採ってきてくれる。

chooseBigger(1,2) // => 2
chooseBigger("a","b") // => b
chooseBigger(1L,2L) // => (Long,Long)=>Long が定義していないためNotFoundエラー

ここまで理解できれば、View Bound / Context Bound は、そんなに難しくないです。

view bound とは

 def f1[T](implicit f2: T => A[T]) は、

 def f1[T <% A[T]] と書ける

このシンタックスシュガーが、View Boundと呼ばれている機能。

例)

trait Comparable[T]{
  def bigger(b:T):T
}
implicit def intComparable( a:Int ) = new Comparable[Int]{
  def bigger(b:Int):Int = Math.max(a,b)
}
implicit def stringComparable( a:String ) = new Comparable[String]{
  def bigger(b:String):String = if( a.compareTo(b) > 0 ) a else b
}

//ここでimplicit conversionは効いているので、

1.bigger(4)
"z".bigger("a")

//などとできますが、これらの暗黙変換を内部で利用する関数は、次のように書けて、

def chooseBigger2[T](a:T,b:T)(implicit comp: T => Comparable[T] ) : T = a.bigger(b)

chooseBigger2(1,2) // => 2
chooseBigger2("a","b") // => b

//chooseBigger2 のシンタックスシュガーとして以下のように書ける。
//(コンパイラがchooseBigger2の形に展開してくれる)

def chooseBigger3[T <% Comparable[T]](a:T,b:T) : T = a.bigger(b)
chooseBigger3(1,2)
chooseBigger3("a","b")


context bound とは

 def f[T]( implicit a:A[T] )

 def f[T:A] と書ける

このシンタックスシュガーが、Context Bound。
※Scala2.8からの導入です。

例)

//ここでは、単純に2つの引数を比較する比較メソッドを考える。
trait Comparator[T] {
  def bigger(a:T,b:T):T
}
implicit object IntComparator extends Comparator[Int]{
  def bigger(a:Int, b:Int):Int = Math.max(a,b)
}
implicit object StringComparator extends Comparator[String]{
  def bigger(a:String, b:String):String = if( a.compareTo(b) > 0 ) a else b
}

def chooseBigger4[T](a:T,b:T)( implicit comp:Comparator[T] ):T = comp.bigger(a,b)

chooseBigger4(1,2)
chooseBigger4("a","b")

//chooseBigger4は次のようにも書ける。

def chooseBigger5[T:Comparator](a:T,b:T):T = implicitly[Comparator[T]].bigger(a,b)

chooseBigger5(1,2)
chooseBigger5("a","b")

//chooseBigger4では、参照compを利用できましたが、
//chooseBigger5では(コード上では)参照が消えてしまうので、使いたいときは、
//implicitly[A[T]]で参照を取得できます。

コメント
匿名さん
2010/10/15
「いいね!」ボタンがあったら押してますよ。
ありがとうございます。

コメントしてください
お名前:
入力しなければ「匿名さん」。20字以内。

メール:
入力しても表示しません

URL:
入力すればリンクが貼れます


コメント: