「Example8.1」の編集履歴(バックアップ)一覧はこちら
Example8.1 - (2011/02/24 (木) 08:41:37) の1つ前との変更点
追加された行は緑色になります。
削除された行は赤色になります。
#co(){
8.1 Type Parameter Bounds
Now that we know how to make classes generic it is natural to generalize some of the earlier classes we have written. For instance class IntSet could be generalized to sets with arbitrary element types. Let's try. The abstract class for generic sets is easily written.
}
** 8.1 型パラメータの境界
クラスをジェネリックにする方法を知った今では、前に書いたクラスの中には一般化した方が自然なものがあります。たとえばクラス IntSet は、任意の要素型を持てるように一般化できます。やってみましょう。ジェネリックな集合の抽象クラスは簡単に書けます。
abstract class Set[A] {
def incl(x: A): Set[A]
def contains(x: A): Boolean
}
#co(){
However, if we still want to implement sets as binary search trees, we encounter a problem. The contains and incl methods both compare elements using methods < and >. For IntSet this was OK, since type Int has these two methods. But for an arbitrary type parameter a, we cannot guarantee this. Therefore, the previous implementation of, say, contains would generate a compiler error.
}
しかしもし二分木として実装し続けたいなら、問題に直面します。メソッド contains と incl はどちらも、要素をメソッド < と > を使って比較します。IntSet については、これは OK です。なぜなら Int はそれら2つのメソッドを持っているからです。しかし任意の型パラメータ A に対しては、それは保証できません。したがって先の実装、たとえば contains ではコンパイルエラーが生じるでしょう。
def contains(x: Int): Boolean =
if (x < elem) left contains x
^ < not a member of type A.
#co(){
One way to solve the problem is to restrict the legal types that can be substituted for type A to only those types that contain methods < and > of the correct types. There is a trait Ordered[A] in the standard class library Scala which represents values which are comparable (via < and >) to values of type A. This trait is defined as follows:
}
問題を解決する一つの方法は、型 A と置き換え可能な正当な型を、正しい型のメソッド < と > を持つ型だけに制限することです。Scala 標準ライブラリには、型 A の値と (< と > によって) 比較可能な値を表現する、トレイト Ordered[A] があります。このトレイトは次のように定義されています。
/** データを完全に順序づけるためのクラス */
trait Ordered[A] {
/** this をオペランド that と比較した結果。
* returns 'x' where
* x < 0 iff this < that
* x == 0 iff this == that
* x > 0 iff this > that
*/
def compare(that: A): Int
def < (that: A): Boolean = (this compare that) < 0
def > (that: A): Boolean = (this compare that) > 0
def <= (that: A): Boolean = (this compare that) <= 0
def >= (that: A): Boolean = (this compare that) >= 0
def compareTo(that: A): Int = compare(that)
}
#co(){
We can enforce the comparability of a type by demanding that the type is a subtype of Ordered. This is done by giving an upper bound to the type parameter of Set:
}
型が Ordered のサブタイプであることを要求することで、互換性を強制できます。これは Set の型パラメータに上界境界(upper bound)を与えることでなされます。
trait Set[A <: Ordered[A]] {
def incl(x: A): Set[A]
def contains(x: A): Boolean
}
#co(){
The parameter declaration A <: Ordered[A] introduces A as a type parameter which must be a subtype of Ordered[A], i.e. its values must be comparable to values of the same type.
}
引数宣言 A <: Ordered[A] は型パラメータとしての A を、A は Ordered[A] のサブタイプでなくてはならない、として導入します。すなわち、その値は同じ型の値と比較可能でなくてはなりません。
#co(){
With this restriction, we can now implement the rest of the generic set abstraction as we did in the case of IntSets before.
}
この制限によって、ジェネリックな集合の抽象化を、前の IntSet の場合と同じように実装できます。
class EmptySet[A <: Ordered[A]] extends Set[A] {
def contains(x: A): Boolean = false
def incl(x: A): Set[A] = new NonEmptySet(x, new EmptySet[A], new EmptySet[A])
}
class NonEmptySet[A <: Ordered[A]]
(elem: A, left: Set[A], right: Set[A]) extends Set[A] {
def contains(x: A): Boolean =
if (x < elem) left contains x
else if (x > elem) right contains x
else true
def incl(x: A): Set[A] =
if (x < elem) new NonEmptySet(elem, left incl x, right)
else if (x > elem) new NonEmptySet(elem, left, right incl x)
else this
}
#co(){
Note that we have left out the type argument in the object creations new NonEmptySet(...). In the same way as for polymorphic methods, missing type arguments in constructor calls are inferred from value arguments and/or the expected result type.
}
オブジェクト生成 new NonEmptySet(...) において、型パラメータを書いていないことに注意して下さい。多相的メソッドと同様に、コンストラクタ呼び出しで型パラメータが書かれていない時には、型パラメータは値引数と期待される結果型(戻り値型)から推論されます。
#co(){
Here is an example that uses the generic set abstraction. Let's first create a subclass of Ordered, like this:
}
以下はジェネリックな集合の抽象化を使う例です。はじめに、Ordered のサブクラスを次のように作りましょう。
case class Num(value: Double) extends Ordered[Num] {
def compare(that: Num): Int =
if (this.value < that.value) -1
else if (this.value > that.value) 1
else 0
}
#co(){
Then:
}
すると
val s = new EmptySet[Num].incl(Num(1.0)).incl(Num(2.0))
s.contains(Num(1.5))
#co(){
This is OK, as type Num implements the trait Ordered[Num]. However, the following example is in error.
}
これは OK です。なぜなら型 Num はトレイト Ordered[Num] を実装しているからです。しかし次の例はエラーになります。
val s = new EmptySet[java.io.File]
^ java.io.File does not conform to type
parameter bound Ordered[java.io.File].
#co(){
One probem with type parameter bounds is that they require forethought: if we had not declared Num a subclass of Ordered, we would not have been able to use Num elements in sets. By the same token, types inherited from Java, such as Int, Double, or String are not subclasses of Ordered, so values of these types cannot be used as set elements.
}
型パラメータ境界の問題は、前もって考えておくべきことです。もし Num を Ordered のサブクラスとして宣言していなければ、Num を集合の要素として使用できません。同様に、Java から継承した Int、Double、String といった型は Ordered のサブクラスではないので、それらの型の値は集合の要素として使用できません。
#co(){
A more flexible design, which admits elements of these types, uses view bounds instead of the plain type bounds we have seen so far. The only change this entails in the example above is in the type parameters:
}
それらの型を要素として許すもっと柔軟なデザインがあります。&bold(){可視境界}(view bound)を今までに見てきた単純な型境界の代わりに使うことです。先の例でこれによって起こる変更は、単に型パラメータが次のようになることです。
trait Set[A <% Ordered[A]] ...
class EmptySet[A <% Ordered[A]] ...
class NonEmptySet[A <% Ordered[A]] ...
#co(){
View bounds <% are weaker than plain bounds <:: A view bounded type parameter clause [A <% T] only specifies that the bounded type A must be convertible to the bound type T, using an implicit conversion.
}
可視境界 <% は通常の上限境界 <: より弱いです。可視境界をもつ型パラメータ節 [A <% T] は単に、境界づけられる型 A が境界となる型 T へ、暗黙の型変換を使って&bold(){変換可能}なことだけを指定します。
#co(){
The Scala library predefines implicit conversions for a number of types, including the primitive types and String. Therefore, the redesign set abstraction can be instantiated with these types as well. More explanations on implicit conversions and view bounds are given in Section 15.
}
Scala ライブラリは、プリミティブ型や String を含む数多くの型について、暗黙の型変換を事前に定義しています。したがって、再デザインされた集合の抽象化は、これらの型についてもインスタンス化できます。暗黙の変換と可視境界に関する更なる説明は第 15 章にあります。
#center(){[[前ページ>Chapter 8 Generic Types and Methods]] [[ 8 章>Chapter 8 Generic Types and Methods]] [[目次>ScalaByExample和訳]] [[次ページ>Example8.2]]}
----
- bound, type bound, view bound の良い訳語が判らない...。 -- tmiya (2008-05-19 00:34:40)
- 束縛、っていっちゃうとやっぱまずいですかね。「縛り」の方がまし? -- a (2009-07-25 03:51:29)
#comment
#co(){
8.1 Type Parameter Bounds
Now that we know how to make classes generic it is natural to generalize some of the earlier classes we have written. For instance class IntSet could be generalized to sets with arbitrary element types. Let's try. The abstract class for generic sets is easily written.
}
#setmenu2(ex-r-menu)
** 8.1 型パラメータの境界
クラスをジェネリックにする方法を知った今では、前に書いたクラスの中には一般化した方が自然なものがあります。たとえばクラス IntSet は、任意の要素型を持てるように一般化できます。やってみましょう。ジェネリックな集合の抽象クラスは簡単に書けます。
abstract class Set[A] {
def incl(x: A): Set[A]
def contains(x: A): Boolean
}
#co(){
However, if we still want to implement sets as binary search trees, we encounter a problem. The contains and incl methods both compare elements using methods < and >. For IntSet this was OK, since type Int has these two methods. But for an arbitrary type parameter a, we cannot guarantee this. Therefore, the previous implementation of, say, contains would generate a compiler error.
}
しかしもし二分木として実装し続けたいなら、問題に直面します。メソッド contains と incl はどちらも、要素をメソッド < と > を使って比較します。IntSet については、これは OK です。なぜなら Int はそれら2つのメソッドを持っているからです。しかし任意の型パラメータ a に対しては、それは保証できません。したがって先の実装、たとえば contains ではコンパイルエラーが生じるでしょう。
def contains(x: Int): Boolean =
if (x < elem) left contains x
^ < not a member of type A.
#co(){
One way to solve the problem is to restrict the legal types that can be substituted for type A to only those types that contain methods < and > of the correct types. There is a trait Ordered[A] in the standard class library Scala which represents values which are comparable (via < and >) to values of type A. This trait is defined as follows:
}
問題を解決する一つの方法は、型 A と置き換え可能な正当な型を、正しい型のメソッド < と > を持つ型だけに制限することです。Scala 標準ライブラリには、型 A の値と (< と > によって) 比較可能な値を表現する、トレイト Ordered[A] があります。このトレイトは次のように定義されています。
/** データを完全に順序づけるためのクラス */
trait Ordered[A] {
/** this をオペランド that と比較した結果。
* returns 'x' where
* x < 0 iff this < that
* x == 0 iff this == that
* x > 0 iff this > that
*/
def compare(that: A): Int
def < (that: A): Boolean = (this compare that) < 0
def > (that: A): Boolean = (this compare that) > 0
def <= (that: A): Boolean = (this compare that) <= 0
def >= (that: A): Boolean = (this compare that) >= 0
def compareTo(that: A): Int = compare(that)
}
#co(){
We can enforce the comparability of a type by demanding that the type is a subtype of Ordered. This is done by giving an upper bound to the type parameter of Set:
}
型が Ordered のサブタイプであることを要求することで、互換性を強制できます。これは Set の型パラメータに上界境界(upper bound)を与えることでなされます。
trait Set[A <: Ordered[A]] {
def incl(x: A): Set[A]
def contains(x: A): Boolean
}
#co(){
The parameter declaration A <: Ordered[A] introduces A as a type parameter which must be a subtype of Ordered[A], i.e. its values must be comparable to values of the same type.
}
パラメータ宣言 A <: Ordered[A] は型パラメータとしての A を、A は Ordered[A] のサブタイプでなくてはならない、として導入します。すなわち、その値は同じ型の値と比較可能でなくてはなりません。
#co(){
With this restriction, we can now implement the rest of the generic set abstraction as we did in the case of IntSets before.
}
この制限によって、ジェネリックな集合の抽象化を、前の IntSet の場合と同じように実装できます。
class EmptySet[A <: Ordered[A]] extends Set[A] {
def contains(x: A): Boolean = false
def incl(x: A): Set[A] = new NonEmptySet(x, new EmptySet[A], new EmptySet[A])
}
class NonEmptySet[A <: Ordered[A]]
(elem: A, left: Set[A], right: Set[A]) extends Set[A] {
def contains(x: A): Boolean =
if (x < elem) left contains x
else if (x > elem) right contains x
else true
def incl(x: A): Set[A] =
if (x < elem) new NonEmptySet(elem, left incl x, right)
else if (x > elem) new NonEmptySet(elem, left, right incl x)
else this
}
#co(){
Note that we have left out the type argument in the object creations new NonEmptySet(...). In the same way as for polymorphic methods, missing type arguments in constructor calls are inferred from value arguments and/or the expected result type.
}
オブジェクト生成 new NonEmptySet(...) において、型引数を書いていないことに注意して下さい。多相的メソッドと同様に、コンストラクタ呼び出しで型引数が書かれていない時、それは値引数と期待される結果型(戻り値型)から推論されます。
#co(){
Here is an example that uses the generic set abstraction. Let's first create a subclass of Ordered, like this:
}
以下はジェネリックな集合の抽象化を使う例です。まづ、Ordered のサブクラスを次のように作りましょう。
case class Num(value: Double) extends Ordered[Num] {
def compare(that: Num): Int =
if (this.value < that.value) -1
else if (this.value > that.value) 1
else 0
}
#co(){
Then:
}
すると
val s = new EmptySet[Num].incl(Num(1.0)).incl(Num(2.0))
s.contains(Num(1.5))
#co(){
This is OK, as type Num implements the trait Ordered[Num]. However, the following example is in error.
}
これは OK です。なぜなら型 Num はトレイト Ordered[Num] を実装しているからです。しかし次の例はエラーになります。
val s = new EmptySet[java.io.File]
^ java.io.File does not conform to type
parameter bound Ordered[java.io.File].
#co(){
One probem with type parameter bounds is that they require forethought: if we had not declared Num a subclass of Ordered, we would not have been able to use Num elements in sets. By the same token, types inherited from Java, such as Int, Double, or String are not subclasses of Ordered, so values of these types cannot be used as set elements.
}
型パラメータ境界の問題は、前もって考えておくべきことです。もし Num を Ordered のサブクラスとして宣言していなければ、Num を集合の要素として使用できません。同様に、Java から継承した Int、Double、String といった型は Ordered のサブクラスではないので、それらの型の値は集合の要素として使用できません。
#co(){
A more flexible design, which admits elements of these types, uses view bounds instead of the plain type bounds we have seen so far. The only change this entails in the example above is in the type parameters:
}
それらの型を要素として許すもっと柔軟なデザインがあります。&bold(){可視境界}(view bound)を今までに見てきた単純な型境界の代わりに使うことです。先の例でこれによって起こる変更は、単に型パラメータが次のようになることです。
trait Set[A <% Ordered[A]] ...
class EmptySet[A <% Ordered[A]] ...
class NonEmptySet[A <% Ordered[A]] ...
#co(){
View bounds <% are weaker than plain bounds <:: A view bounded type parameter clause [A <% T] only specifies that the bounded type A must be convertible to the bound type T, using an implicit conversion.
}
可視境界 <% は通常の上限境界 <: より弱いです。可視境界をもつ型パラメータ節 [A <% T] は単に、境界づけられる型 A が境界となる型 T へ、暗黙の型変換を使って&bold(){変換可能}なことだけを指定します。
#co(){
The Scala library predefines implicit conversions for a number of types, including the primitive types and String. Therefore, the redesign set abstraction can be instantiated with these types as well. More explanations on implicit conversions and view bounds are given in Section 15.
}
Scala ライブラリは、プリミティブ型や String を含む数多くの型について、暗黙の型変換を事前に定義しています。したがって、再デザインされた集合の抽象化は、これらの型についてもインスタンス化できます。暗黙の変換と可視境界に関する更なる説明は第 15 章にあります。
#center(){[[前ページ>Chapter 8 Generic Types and Methods]] [[ 8 章>Chapter 8 Generic Types and Methods]] [[目次>ScalaByExample和訳]] [[次ページ>Example8.2]]}
----
- bound, type bound, view bound の良い訳語が判らない...。 -- tmiya (2008-05-19 00:34:40)
- 束縛、っていっちゃうとやっぱまずいですかね。「縛り」の方がまし? -- a (2009-07-25 03:51:29)
#comment