Scalaのコンテキストとビューの境界とは何ですか?


267

簡単に言えば、コンテキストとビューの境界とは何ですか?それらの違いは何ですか?

わかりやすい例もいくつかあります。

回答:


477

これはすでに尋ねられたと思いましたが、そうだとすれば、「関連」バーに質問が表示されません。だから、ここにあります:

ビューバウンドとは何ですか?

バインドビューは、いくつかの種類の使用を可能にするために、Scalaで導入された仕組みだったA かのように、それはいくつかのタイプでしたB。典型的な構文はこれです:

def f[A <% B](a: A) = a.bMethod

言い換えると、タイプのオブジェクトでメソッドを呼び出すことができるようにA、暗黙的にB利用可能に変換する必要があります。標準ライブラリ(とにかくScala 2.8.0より前)でのビュー境界の最も一般的な使用法は、次のようにで使用されます。BAOrdered

def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b

一方が変換できるためAOrdered[A]、そしてためOrdered[A]の方法を定義し<(other: A): Boolean、Iは式を使用することができますa < b

ビューの境界は非推奨であることに注意してください。これらは避けてください。

コンテキストバウンドとは何ですか?

コンテキスト境界はScala 2.8.0で導入されたもので、通常、いわゆる型クラスパターン(Haskell型クラスによって提供される機能をより詳細な方法でエミュレートするコードのパターン)で使用されます。

ビューの境界は単純な型(などA <% String)で使用できますが、コンテキストの境界には上記のようなパラメーター化された型が必要ですOrdered[A]が、とは異なりStringます。

コンテキストバウンドは、ビューバウンドの暗黙的な変換ではなく、暗黙的な値を表します。これは、一部のtypeについて、利用可能なtypeの暗黙的な値があることを宣言するために使用されます。構文は次のようになります。AB[A]

def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]

これは、使用方法がすぐに明確ではないため、ビューバウンドよりも混乱します。Scalaでの一般的な使用例は次のとおりです。

def f[A : ClassManifest](n: Int) = new Array[A](n)

Arrayパラメータ化された型の初期化では、ClassManifest型の消去と配列の非消去の性質に関連する難解な理由により、が使用可能である必要があります。

ライブラリのもう1つの非常に一般的な例は、もう少し複雑です。

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)

ここでimplicitlyは、必要な暗黙の値(typeの1つ)を取得するために使用されます。Ordering[A]このクラスはメソッドを定義しcompare(a: A, b: A): Intます。

これを行う別の方法を以下に示します。

ビュー境界とコンテキスト境界はどのように実装されますか?

ビューの境界とコンテキストの境界の両方が、その定義を前提として、暗黙のパラメーターで実装されていることは驚くべきことではありません。実際、私が示した構文は、実際に何が起きるかを表す構文上の糖衣です。彼らが砂糖を取り除く方法を以下に示します:

def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod

def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)

したがって、当然のことながら、完全な構文でそれらを記述できます。これは、コンテキストの境界に特に役立ちます。

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)

ビュー境界は何に使用されますか?

ビューの境界は、主にpimp myライブラリパターンを利用するために使用されます。これにより、元の型を何らかの方法で返したい場合に、既存のクラスにメソッドを「追加」します。なんらかの方法でその型を返す必要がない場合は、ビューのバインドは必要ありません。

ビューにバインドされた使用法の典型的な例は、の処理Orderedです。は暗黙的な変換がありますが、たとえばでIntはないことに注意してくださいOrdered。前に示した例は、変換されていない型を返すため、ビューバインドが必要です。

def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b

この例は、ビュー境界がないと機能しません。ただし、別のタイプを返す場合、ビューをバインドする必要はもうありません。

def f[A](a: Ordered[A], b: A): Boolean = a < b

ここでの変換(必要な場合)は、パラメーターをに渡す前に行われるためf、そのfことを知る必要はありません。

加えてOrdered、ライブラリからの最も一般的な使用法は、Scalaコレクションと同様に、JavaクラスであるStringおよびの処理Arrayです。例えば:

def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b

一つのビュー際限なくこれを行うことを試みた場合、の戻り型がStringなりWrappedString、同様のため(スカラ2.8) Array

型が戻り型の型パラメーターとしてのみ使用されている場合でも、同じことが起こります。

def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted

コンテキスト境界は何に使用されますか?

コンテキスト境界は、主にHaskellの型クラスへの参照として、typeclass patternと呼ばれるもので使用されます。基本的に、このパターンは、一種の暗黙的なアダプターパターンを介して機能を使用可能にすることにより、継承の代替手段を実装します。

典型的な例はScala 2.8でOrderingOrderedScalaのライブラリ全体で置き換えられています。使用法は次のとおりです。

def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b

ただし、通常は次のように記述されています。

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
    import ord.mkOrderingOps
    if (a < b) a else b
}

これはOrdering、従来の演算子スタイルを可能にする内部の暗黙的な変換を利用しています。Scala 2.8のもう1つの例は次のNumericとおりです。

def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)

より複雑な例は、の新しいコレクションの使用法ですCanBuildFromが、これについては非常に長い回答がすでにあるため、ここではそれを避けます。そして、前述のように、ClassManifest具体的な型なしで新しい配列を初期化するために必要な使用法があります。

typeclassパターンにバインドされたコンテキストは、懸念の分離を可能にするため、独自のクラスで使用される可能性がはるかに高くなります。一方、ビューの境界は、適切な設計によって独自のコードで回避できます(主に他の誰かの設計を回避するために使用されます) )。

長い間可能でしたが、コンテキストの境界の使用は2010年に本格的に始まり、現在、Scalaの最も重要なライブラリとフレームワークのほとんどである程度使用されています。ただし、その最も極端な使用例は、Scalazライブラリであり、Haskellの多くの機能をScalaにもたらします。型クラスのパターンを読んで、それを使用できるすべての方法をよく理解することをお勧めします。

編集

関心のある関連質問:


9
本当にありがとうございました。私はこれが以前に答えられたことを知っています、そしておそらく私は十分に注意深く読まなかったかもしれませんが、あなたのここの説明は私が見た中で最も明確なものです。それではまたよろしくお願いします。
chrsan 2010

3
@chrsan私はさらに2つのセクションを追加し、それぞれがどこで使用されるかについて詳しく説明しました。
Daniel C. Sobral

2
これは素晴らしい説明だと思います。よろしければ、ドイツ語のブログ(dgronau.wordpress.com)で翻訳したいと思います。
Landei、

3
これは、これまでに見つけたこのトピックの最も優れた最も包括的な説明です。どうもありがとうございます!
fotNelton 2011

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.