Spec2.8Chap12b

「Spec2.8Chap12b」の編集履歴(バックアップ)一覧はこちら

Spec2.8Chap12b」(2011/02/23 (水) 18:42:34) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

#setmenu2(spec2.8-r-menu) &aname(12.3,option=nolink){ } ** 12.3 標準的な参照クラス (Standard Reference Classes) #co(){----------------------------------------------------- bgn-hide0} This section presents some standard Scala reference classes which are treated in a special way in Scala compiler - either Scala provides syntactic sugar for them, or the Scala compiler generates special code for their operations . Other classes in the standard Scala library are documented in the Scala library documentation by HTML pages . #co(){--------------------------------------------------- end-hide0} この節では、Scala コンパイラ中で特別な方法で扱われる、 いくつかの標準的な Scala 参照クラスを紹介します。 Scala はそれらのために糖衣構文を提供するか、 あるいは、Scala コンパイラは操作ための特別なコードを生成します。 標準 Scala ライブラリ中の他のクラスは、Scala ライブラリドキュメント中に HTML ページの形で文書化されています。 &br() &br() &aname(12.3.1,option=nolink){ } *** 12.3.1 クラス String (Class String) #co(){----------------------------------------------------- bgn-hide0} Scala's String class is usually derived from the standard String class of the underlying host system (and may be identified with it). For Scala clients the class is taken to support in each case a method #co(){--------------------------------------------------- end-hide0} Scala の文字列クラスは通常、ホストシステムの標準的な String クラスから派生されます(それと同一視されているかもしれません)。 Scala クライアントに対して、クラスはそれぞれの場合に応じて、 次のメソッドをサポートするとされます。 #co(){----------------------------------------------------- bgn-code} def + (that: Any): String #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} which concatenates its left operand with the textual representation of its right operand . #co(){--------------------------------------------------- end-hide0} これは、その左オペランドと右オペランドのテキスト表現を連結します。 &br() &br() &aname(12.3.2,option=nolink){ } *** 12.3.2 タプルクラス (The Tuple Classes) #co(){----------------------------------------------------- bgn-hide0} Scala defines tuple classes Tuplen for n = 2,..., 9. These are defined as follows . #co(){--------------------------------------------------- end-hide0} Scala は、n = 2,...,9 に対して、タプルクラス Tuplen を定義しています。 それらは次のように定義されています。 #co(){----------------------------------------------------- bgn-code} package scala case class Tuplen[+a_1,..., +a_n](_1: a_1,..., _n : a_n) { def toString = "(" ++ _1 ++ "," ++ ... ++ "," ++ _n ++ ")" } #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} The implicitly imported predef object (§12.5) defines the names Pair as an alias of Tuple2 and Triple as an alias for Tuple3 . #co(){--------------------------------------------------- end-hide0} 暗黙のうちにインポートされた predef(事前定義済み)オブジェクト (&link_anchor(12.5,page=Spec2.8Chap12b){§12.5})は、 Pair という名前の Tuple2 のエイリアスと、 Tripleという名前の Tuple3 のエイリアスを定義しています。 &br() &br() &aname(12.3.3,option=nolink){ } *** 12.3.3 関数クラス (The Function Classes) #co(){----------------------------------------------------- bgn-hide0} Scala defines function classes Functionn for n = 1,..., 9. These are defined as follows . #co(){--------------------------------------------------- end-hide0} Scala は、n = 1,...,9 に対して、関数クラス Functionn を定義しています。 それらは次のように定義されています。 #co(){----------------------------------------------------- bgn-code} package scala trait Functionn[-a_1,..., -a_n , +b] { def apply(x_1: a_1,..., x_n : a_n): b def toString = "<function>" } #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} A subclass of Function1 represents partial functions, which are undefined on some points in their domain . In addition to the apply method of functions, partial functions also have a isDefined method, which tells whether the function is defined at the given argument: #co(){--------------------------------------------------- end-hide0} Function1 のサブクラスは部分関数を表し、 そのドメインのいくつかの点で未定義です。 関数の apply メソッドに加えて、 部分関数も isDefined メソッドを持っており、それは、 与えられた引数で関数が定義されているかどうかを答えます。: #co(){----------------------------------------------------- bgn-code} class PartialFunction[-A, +B] extends Function1[A, B] { def isDefinedAt(x: A): Boolean } #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} The implicitly imported predef object (§12.5) defines the name Function as an alias of Function1 . #co(){--------------------------------------------------- end-hide0} 暗黙のうちにインポートされる predefオブジェクト (&link_anchor(12.5,page=Spec2.8Chap12b){§12.5})は、 名前 Function を Function1 のエイリアスと定義しています。 &br() &br() &aname(12.3.4,option=nolink){ } *** 12.3.4 クラス Array (Class Array) ジェネリックな配列クラスは、次のように与えられています。 #co(){----------------------------------------------------- bgn-code} final class Array[A](len: Int) extends Seq[A] { def length: Int = len def apply(i: Int): A = ... def update(i: Int, x: A): Unit = ... def elements: Iterator[A] = ... def subArray(from: Int, end: Int): Array[A] = ... def filter(p: A => Boolean): Array[A] = ... def map[B](f: A => B): Array[B] = ... def flatMap[B](f: A => Array[B]): Array[B] = ... } #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} If T is not a type parameter or abstract type, the type Array[T] is represented as the native array type []T in the underlying host system . In that case length returns the length of the array, apply means subscripting, and update means element update . #co(){--------------------------------------------------- end-hide0} もし T が型パラメータあるいは抽象型でないなら、型 Array[T] は ホストシステム中のネイティブな配列型 []T として表現されます。 そのような場合、length は配列の長さを返し、apply は添え字指定を意味し、 update は要素の更新を意味します。 #co(){----------------------------------------------------- bgn-hide0} Because of the syntactic sugar for apply and update operations (§6.26), we have the following correspondences between Scala and Java/C# code for operations on an array xs: #co(){--------------------------------------------------- end-hide0} apply と update 操作 (&link_anchor(6.26,page=Spec2.8Chap6d){§6.26}) の糖衣構文のおかげで、配列 xs の操作について、 Scala と Java/C# のコード間に次の対応があります。: #co(){----------------------------------------------------- bgn-code} Scala Java/C# xs.length xs.length xs(i) xs[i] xs(i) = e xs[i] = e #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} Arrays also implement the sequence trait scala.Seq by defining an elements method which returns all elements of the array in an Iterator . #co(){--------------------------------------------------- end-hide0} 配列は、イテレータ中の配列のすべての要素を返す elements メソッドを定義することで、シーケンストレイト scala.Seq も実装しています。 #co(){----------------------------------------------------- bgn-hide0} Because of the tension between parametrized types in Scala and the ad-hoc implementation of arrays in the host-languages, some subtle points need to be taken into account when dealing with arrays . These are explained in the following . #co(){--------------------------------------------------- end-hide0} Scala におけるパラメータ化された型と、 ホスト言語における配列のアドホックな実装間の緊張関係のため、 配列を取り扱うとき、いくつかの微妙な点を考慮する必要があります。 それらを次に説明します。 #co(){----------------------------------------------------- bgn-hide0} First, unlike arrays in Java or C#, arrays in Scala are not co-variant; That is, S <: T does not imply Array[S] <: Array[T] in Scala . However, it is possible to cast an array of S to an array of T if such a cast is permitted in the host environment . For instance Array[String] does not conform to Array[Object], even though String conforms to Object . However, it is possible to cast an expression of type Array[String] to Array[Object], and this cast will succeed without raising a ClassCastException . #co(){--------------------------------------------------- end-hide0} 最初に、Java あるいは C# 中の配列と異なり、Scala 中の配列は共変&strong(){ではありません}。;すなわち、Scalaでは、 S <: T が Array[S] <: Array[T] を意味しません。 しかし、S の配列をキャストして T の配列にすることは、 もしそのようなキャストがホスト環境で許されるなら、可能です。 たとえば、String は Objectに適合しますが、インスタンス Array[String] は Array[Object] に適合しません。 しかし、型 Array[String] の式を型 Array[Object] へキャストすることは可能であり、このキャストは ClassCastException を引き起こすことなく成功します。 例: #co(){----------------------------------------------------- bgn-code} val xs = new Array[String](2) // val ys: Array[Object] = xs // **** error: 非互換な型 val ys: Array[Object] = xs.asInstanceOf[Array[Object]] // OK #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} Second, for polymorphic arrays, that have a type parameter or abstract type T as their element type, a representation different from []T might be used. However, it is guaranteed that isInstanceOf and asInstanceOf still work as if the array used the standard representation of monomorphic arrays: #co(){--------------------------------------------------- end-hide0} 第二に、その要素型として型パラメータあるいは抽象型 T を持つ &strong(){多相的配列}に対して、[]T と異なる表現が使われることがあります。 しかし、isInstanceOf と asInstanceOf があたかも配列が単相的配列の標準的な表現を使うかのように、 それでも動作することは保証されています。: #co(){----------------------------------------------------- bgn-code} val ss = new Array[String](2) def f[T](xs: Array[T]): Array[String] = if (xs.isInstanceOf[Array[String]]) xs.asInstanceOf[Array[String]) else throw new Error("not an instance") f(ss) // ss を返す #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} The representation chosen for polymorphic arrays also guarantees that polymorphic array creations work as expected . An example is the following implementation of method mkArray, which creates an array of an arbitrary type T , given a sequence of T's which defines its elements . #co(){--------------------------------------------------- end-hide0} 多相的配列用に選ばれた表現は、 多相的配列の生成が期待どおり動作することも保証しています。 次の例はメソッド mkArray の実装で、その要素を定義する T のシーケンスを与えられ、任意の型 T の配列を生成します。 #co(){----------------------------------------------------- bgn-code} def mkArray[T](elems: Seq[T]): Array[T] = { val result = new Array[T](elems.length) var i = 0 for (elem <- elems) { result(i) = elem i += 1 } } #co(){--------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} Note that under Java's erasure model of arrays the method above would not work as expected - in fact it would always return an array of Object . #co(){--------------------------------------------------- end-hide0} Java の配列の型消去モデルの下では、上のメソッドが期待通りには動作しない --- 実際、それは常に Object の配列を返す --- ことに注意してください。 #co(){----------------------------------------------------- bgn-hide0} Third, in a Java environment there is a method System.arraycopy which takes two objects as parameters together with start indices and a length argument, and copies elements from one object to the other, provided the objects are arrays of compatible element types . System.arraycopy will not work for Scala's polymorphic arrays because of their different representation . One should instead use method Array.copy which is defined in the companion object of class Array . This companion object also defines various constructor methods for arrays, as well as the extractor method unapplySeq (§8.1.8) which enables pattern matching over arrays . #co(){--------------------------------------------------- end-hide0} 第三に、Java 環境ではメソッド System.arraycopy があります。それは、 2 つのオブジェクトをパラメータにとると共に、開始インデックスと長さの引数を もち、オブジェクトは互換の要素型からなる配列であるとして、 1 つのオブジェクトから他方へ要素をコピーします (訳注:arraycopy(Object src, int srcPos, Object dest, int destPos, int length) )。 System.arraycopy は、Scala の多相的配列に対しては機能しません。 なぜなら、それらの表現が異なるからです。 その代わりに Array.copy を使うべきです。 それはクラス Array のコンパニオンオブジェクト中で定義されています。 このコンパニオンオブジェクトも、 配列上のパターンマッチングを可能にする抽出子メソッド unapplySeq (&link_anchor(8.1.8,page=Spec2.8Chap8a){§8.1.8})と同様、 配列のために種々のコンストラクタメソッドを定義しています。 #co(){----------------------------------------------------- bgn-code} package scala object Array { /** copies array elements from 'src' to 'dest'. */ /** 'src' から 'dest'へ配列要素をコピー */ def copy(src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int): Unit = ... /** Concatenate all argument arrays into a single array. */ /** 1 つの配列へ、すべての引数配列を連結 */ def concat[T](xs: Array[T]*): Array[T] = ... /** Create a an array of successive integers. */ /** 連続した整数からなる配列を生成 */ def range(start: Int, end: Int): Array[Int] = ... /** Create an array with given elements. */ /** 与えられた要素の配列を生成 */ def apply[A <: AnyRef](xs: A*): Array[A] = ... /** Analogous to above. */ def apply(xs: Boolean*): Array[Boolean] = ... def apply(xs: Byte*) : Array[Byte] = ... def apply(xs: Short*) : Array[Short] = ... def apply(xs: Char*) : Array[Char] = ... def apply(xs: Int*) : Array[Int] = ... def apply(xs: Long*) : Array[Long] = ... def apply(xs: Float*) : Array[Float] = ... def apply(xs: Double*) : Array[Double] = ... def apply(xs: Unit*) : Array[Unit] = ... /** Create an array containing several copies of an element. */ /** 要素の複数のコピーを含む配列の生成 */ def make[A](n: Int, elem: A): Array[A] = { /** Enables pattern matching over arrays */ /** 配列上のパターンマッチングを可能とする */ def unapplySeq[A](x: Array[A]): Option[Seq[A]] = Some(x) } #co(){--------------------------------------------------- end-code} &br() &bold(){Example 12.3.1} 次のメソッドは、与えられた引数配列を複写し、 オリジナルと複写したものからなる、ペアを返します: #co(){----------------------------------------------------- bgn-code} def duplicate[T](xs: Array[T]) = { val ys = new Array[T](xs.length) Array.copy(xs, 0, ys, 0, xs.length) (xs, ys) } #co(){--------------------------------------------------- end-code} &br() &br() &aname(12.4,option=nolink){ } ** 12.4 クラス Node (Class Node) #co(){----------------------------------------------------- bgn-code} package scala.xml trait Node { /** the label of this node */ /** このノードのラベル */ def label: String /** attribute axis */ /** axis 属性 */ def attribute: Map[String, String] /** child axis (all children of this node) */ /** 子 axis (このノードの全ての子) */ def child: Seq[Node] /** descendant axis (all descendants of this node) */ /** 子孫 axis (このノードの全ての子孫) */ def descendant: Seq[Node] = child.toList.flatMap { x => x::x.descendant.asInstanceOf[List[Node]] } /** descendant axis (all descendants of this node) */ /** 子孫 axis (このノードの全ての子孫) */ def descendant_or_self: Seq[Node] = this::child.toList.flatMap { x => x::x.descendant.asInstanceOf[List[Node]] } override def equals(x: Any): Boolean = x match { case that:Node => that.label == this.label && that.attribute.sameElements(this.attribute) && that.child.sameElements(this.child) case _ => false } /** XPath style projection function. Returns all children of this node * that are labeled with 'that'. The document order is preserved. */ /** XPath スタイルの射影関数。'that'と印された、このノードの * 全ての子を返す。ドキュメントの順番は維持される。 */ def \(that: Symbol): NodeSeq = { new NodeSeq({ that.name match { case "_" => child.toList case _ => var res:List[Node] = Nil for (x <- child.elements if x.label == that.name) { res = x::res } res.reverse } }) } /** XPath style projection function. Returns all nodes labeled with the * name 'that' from the 'descendant_or_self' axis. Document order is preserved. */ /** XPath スタイルの射影関数。'子孫または自身' axis から、'that'と * 印されたこのノードの全ての子を返す。ドキュメントの順番は維持される。 */ def \\(that: Symbol): NodeSeq = { new NodeSeq( that.name match { case "_" => this.descendant_or_self case _ => this.descendant_or_self.asInstanceOf[List[Node]]. filter(x => x.label == that.name) }) } /** hashcode for this XML node */ /** この XML ノードに対する ハッシュコード */ override def hashCode = Utility.hashCode(label, attribute.toList.hashCode, child) /** string representation of this node */ /** このノードの文字列表現 */ override def toString = Utility.toXML(this) } #co(){--------------------------------------------------- end-code} &br() &br() &aname(12.5,option=nolink){ } ** 12.5 事前定義済みオブジェクト (The Predef Object) #co(){----------------------------------------------------- bgn-hide0} The predef object defines standard functions and type aliases for Scala programs . It is always implicitly imported, so that all its defined members are available without qualification . Its definition for the JVM environment conforms to the following signature: #co(){--------------------------------------------------- end-hide0} 事前定義済みオブジェクトは Scala プログラムの標準関数と型エイリアスを定義します。 これは常に暗黙のうちにインポートされるので、 その定義されたすべてのメンバーは修飾なしで利用可能です。 JVM 環境での定義は、次のシグニチャに一致します: #co(){----------------------------------------------------- bgn-code} package scala object Predef { // classOf --------------------------------------------------------- /** Returns the runtime representation of a class type. */ /** クラス型の実行時表現を返す */ def classOf[T]: Class[T] = null // this is a dummy, classOf is handled by compiler. // これはダミー。 classOf はコンパイラによって処理される。 // 標準の型エイリアス ------------------------------------------- type byte = scala.Byte type short = scala.Short type char = scala.Char type int = scala.Int type long = scala.Long type float = scala.Float type double = scala.Double type boolean = scala.Boolean type unit = scala.Unit type String = java.lang.String type Class[T] = java.lang.Class[T] type Runnable = java.lang.Runnable type Throwable = java.lang.Throwable type Exception = java.lang.Exception type Error = java.lang.Error type RuntimeException = java.lang.RuntimeException type NullPointerException = java.lang.NullPointerException type ClassCastException = java.lang.ClassCastException type IndexOutOfBoundsException = java.lang.IndexOutOfBoundsException type ArrayIndexOutOfBoundsException = java.lang.ArrayIndexOutOfBoundsException type StringIndexOutOfBoundsException = java.lang.StringIndexOutOfBoundsException type UnsupportedOperationException = java.lang.UnsupportedOperationException type IllegalArgumentException = java.lang.IllegalArgumentException type NoSuchElementException = java.util.NoSuchElementException type NumberFormatException = java.lang.NumberFormatException // その他 ----------------------------------------------------- type Function[-A, +B] = Function1[A, B] type Map[A, B] = collection.immutable.Map[A, B] type Set[A] = collection.immutable.Set[A] val Map = collection.immutable.Map val Set = collection.immutable.Set // エラーとアサーション-------------------------------------------- def error(message: String): Nothing = throw new Error(message) def exit: Nothing = exit(0) def exit(status: Int): Nothing = { java.lang.System.exit(status) throw new Throwable() } def assert(assertion: Boolean) { if (!assertion) throw new java.lang.AssertionError("assertion failed") } def assert(assertion: Boolean, message: Any) { if (!assertion) throw new java.lang.AssertionError("assertion failed: " + message) } def assume(assumption: Boolean) { if (!assumption) throw new IllegalArgumentException("assumption failed") } def assume(assumption: Boolean, message: Any) { if (!assumption) throw new IllegalArgumentException(message.toString) } // tupling --------------------------------------------------------- type Pair[+A, +B] = Tuple2[A, B] object Pair { def apply[A, B](x: A, y: B) = Tuple2(x, y) def unapply[A, B](x: Tuple2[A, B]): Option[Tuple2[A, B]] = Some(x) } type Triple[+A, +B, +C] = Tuple3[A, B, C] object Triple { def apply[A, B, C](x: A, y: B, z: C) = Tuple3(x, y, z) def unapply[A, B, C](x: Tuple3[A, B, C]): Option[Tuple3[A, B, C]] = Some(x) } class ArrowAssoc[A](x: A) { def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y) } implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x) // 印字と読み込み ----------------------------------------------- def print(x: Any) = Console.print(x) def println() = Console.println() def println(x: Any) = Console.println(x) def printf(text: String, xs: Any*) = Console.printf(text, xs: _*) def format(text: String, xs: Any*) = Console.format(text, xs: _*) def readLine(): String = Console.readLine() def readLine(text: String, args: Any*) = Console.readLine(text, args) def readBoolean() = Console.readBoolean() def readByte() = Console.readByte() def readShort() = Console.readShort() def readChar() = Console.readChar() def readInt() = Console.readInt() def readLong() = Console.readLong() def readFloat() = Console.readFloat() def readDouble() = Console.readDouble() def readf(format: String) = Console.readf(format) def readf1(format: String) = Console.readf1(format) def readf2(format: String) = Console.readf2(format) def readf3(format: String) = Console.readf3(format) // The ''catch-all'' implicit ---------------------------------------- implicit def identity[A](x: A): A = x // クラス Ordered へのビュー %% @@@KSW what is ''Proxy''? It's not defined anywhere. %% @@@MO It's a Java interface. implicit def int2ordered(x: Int): Ordered[Int] = new Ordered[Int] with Proxy { def self: Any = x def compare[B >: Int <% Ordered[B]](y: B): Int = y match { case y1: Int => if (x < y1) -1 else if (x > y1) 1 else 0 case _ => -(y compare x) } } // The implementations of following methods are analogous to the last one: // 次のメソッドの実装は、最後の一つに類似 implicit def char2ordered(x: Char): Ordered[Char] = ... implicit def long2ordered(x: Long): Ordered[Long] = ... implicit def float2ordered(x: Float): Ordered[Float] = ... implicit def double2ordered(x: Double): Ordered[Double] = ... implicit def boolean2ordered(x: Boolean): Ordered[Boolean] = ... implicit def seq2ordered[A <% Ordered[A]](xs: Array[A]): Ordered[Seq[A]] = new Ordered[Seq[A]] with Proxy { def compare[B >: Seq[A] <% Ordered[B]](that: B): Int = that match { case that: Seq[A] => var res = 0 val these = this.elements val those = that.elements while (res == 0 && these.hasNext) res = if (!those.hasNext) 1 else these.next compare those.next case _ => - (that compare xs) } implicit def string2ordered(x: String): Ordered[String] = new Ordered[String] with Proxy { def self: Any = x def compare[b >: String <% Ordered[b]](y: b): Int = y match { case y1: String => x compare y1 case _ => -(y compare x) } } implicit def tuple2ordered[a1 <% Ordered[a1], a2 <% Ordered[a2]] (x: Tuple2[a1, a2]): Ordered[Tuple2[a1, a2]] = new Ordered[Tuple2[a1, a2]] with Proxy { def self: Any = x def compare[T >: Tuple2[a1, a2] <% Ordered[T]](y: T): Int = y match { case y: Tuple2[a1, a2] => val res = x._1 compare y._1 if (res == 0) x._2 compare y._2 else res case _ => -(y compare x) } } // Tuple3 ~ Tuple9 についても同様 // クラス Seq へのビュー implicit def string2seq(str: String): Seq[Char] = new Seq[Char] { def length = str.length() def elements = Iterator.fromString(str) def apply(n: Int) = str.charAt(n) override def hashCode: Int = str.hashCode override def equals(y: Any): Boolean = (str == y) override protected def stringPrefix: String = "String" } // プリミティブ型から Java のボックス型へのビュー implicit def byte2Byte(x: Byte) = new java.lang.Byte(x) implicit def short2Short(x: Short) = new java.lang.Short(x) implicit def char2Character(x: Char) = new java.lang.Character(x) implicit def int2Integer(x: Int) = new java.lang.Integer(x) implicit def long2Long(x: Long) = new java.lang.Long(x) implicit def float2Float(x: Float) = new java.lang.Float(x) implicit def double2Double(x: Double) = new java.lang.Double(x) implicit def boolean2Boolean(x: Boolean) = new java.lang.Boolean(x) // 数値変換ビュー implicit def byte2short(x: Byte): Short = x.toShort implicit def byte2int(x: Byte): Int = x.toInt implicit def byte2long(x: Byte): Long = x.toLong implicit def byte2float(x: Byte): Float = x.toFloat implicit def byte2double(x: Byte): Double = x.toDouble implicit def short2int(x: Short): Int = x.toInt implicit def short2long(x: Short): Long = x.toLong implicit def short2float(x: Short): Float = x.toFloat implicit def short2double(x: Short): Double = x.toDouble implicit def char2int(x: Char): Int = x.toInt implicit def char2long(x: Char): Long = x.toLong implicit def char2float(x: Char): Float = x.toFloat implicit def char2double(x: Char): Double = x.toDouble implicit def int2long(x: Int): Long = x.toLong implicit def int2float(x: Int): Float = x.toFloat implicit def int2double(x: Int): Double = x.toDouble implicit def long2float(x: Long): Float = x.toFloat implicit def long2double(x: Long): Double = x.toDouble implicit def float2double(x: Float): Double = x.toDouble } #co(){--------------------------------------------------- end-code} &br() &br() &aname(bibliography,option=nolink){ } ** Bibliography [Dra10] Iulian Dragos. Scala specialization, 2010. SID-9. [KP07] Andrew J. Kennedy and Benjamin C. Pierce. On Decidability of Nominal Subtyping with Variance, January 2007. FOOL-WOOD '07. [Oa04] Martin Odersky and al. An Overview of the Scala Programming Language . Technical Report IC/2004/64, EPFL Lausanne, Switzerland, 2004. [OCRZ03] Martin Odersky, Vincent Cremet, Christine Rockl, and Matthias Zenger. A Nominal Theory of Objects with Dependent Types. In Proc. ECOOP'03, Springer LNCS, July 2003. [Ode06] Martin Odersky. The Scala Experiment - Can We Provide Better Language Support for Component Systems? In Proc. ACM Symposium on Principles of Programming Languages, 2006. [OZ05a] Martin Odersky and Matthias Zenger. Independently Extensible Solutions to the Expression Problem. In Proc. FOOL 12, January 2005. &nolink(http://homepages.inf.ed.ac.uk/wadler/fool) . [OZ05b] Martin Odersky and Matthias Zenger. Scalable Component Abstractions. In Proc. OOPSLA, 2005. [W3C] W3C. Extensible Markup Language (XML). &nolink(http://www.w3.org/TR/REC-xml) . #center(){[[前>Spec2.8Chap12a]] [[目次>Spec2.8和訳]] [[次:ChapA>Spec2.8ChapAa]]}
#setmenu2(spec2.8-r-menu) &aname(12.3,option=nolink){ } ** 12.3 標準的な参照クラス (Standard Reference Classes) This section presents some standard Scala reference classes which are treated in a special way in Scala compiler - either Scala provides syntactic sugar for them, or the Scala compiler generates special code for their operations . Other classes in the standard Scala library are documented in the Scala library documentation by HTML pages . この節では、Scala コンパイラ中で特別な方法で扱われる、 いくつかの標準的な Scala 参照クラスを紹介します。 Scala はそれらのために糖衣構文を提供するか、 あるいは、Scala コンパイラは操作ための特別なコードを生成します。 標準 Scala ライブラリ中の他のクラスは、Scala ライブラリドキュメント中に HTML ページの形で文書化されています。 &br() &br() &aname(12.3.1,option=nolink){ } *** 12.3.1 クラス String (Class String) Scala's String class is usually derived from the standard String class of the underlying host system (and may be identified with it). For Scala clients the class is taken to support in each case a method Scala の文字列クラスは通常、ホストシステムの標準的な String クラスから派生されます(それと同一視されているかもしれません)。 Scala クライアントに対して、クラスはそれぞれの場合に応じて、 次のメソッドをサポートするとされます。 def + (that: Any): String which concatenates its left operand with the textual representation of its right operand . これは、その左オペランドと右オペランドのテキスト表現を連結します。 &br() &br() &aname(12.3.2,option=nolink){ } *** 12.3.2 タプルクラス (The Tuple Classes) Scala defines tuple classes Tuplen for n = 2,..., 9. These are defined as follows . Scala は、n = 2,...,9 に対して、タプルクラス Tuplen を定義しています。 それらは次のように定義されています。 package scala case class Tuplen[+a_1,..., +a_n](_1: a_1,..., _n : a_n) { def toString = "(" ++ _1 ++ "," ++ ... ++ "," ++ _n ++ ")" } The implicitly imported predef object (§12.5) defines the names Pair as an alias of Tuple2 and Triple as an alias for Tuple3 . 暗黙のうちにインポートされた predef(事前定義済み)オブジェクト (&link_anchor(12.5,page=Spec2.8Chap12b){§12.5})は、 Pair という名前の Tuple2 のエイリアスと、 Tripleという名前の Tuple3 のエイリアスを定義しています。 &br() &br() &aname(12.3.3,option=nolink){ } *** 12.3.3 関数クラス (The Function Classes) Scala defines function classes Functionn for n = 1,..., 9. These are defined as follows . Scala は、n = 1,...,9 に対して、関数クラス Functionn を定義しています。 それらは次のように定義されています。 package scala trait Functionn[-a_1,..., -a_n , +b] { def apply(x_1: a_1,..., x_n : a_n): b def toString = "<function>" } A subclass of Function1 represents partial functions, which are undefined on some points in their domain . In addition to the apply method of functions, partial functions also have a isDefined method, which tells whether the function is defined at the given argument: Function1 のサブクラスは部分関数を表し、 そのドメインのいくつかの点で未定義です。 関数の apply メソッドに加えて、 部分関数も isDefined メソッドを持っており、それは、 与えられた引数で関数が定義されているかどうかを答えます。: class PartialFunction[-A, +B] extends Function1[A, B] { def isDefinedAt(x: A): Boolean } The implicitly imported predef object (§12.5) defines the name Function as an alias of Function1 . 暗黙のうちにインポートされる predefオブジェクト (&link_anchor(12.5,page=Spec2.8Chap12b){§12.5})は、 名前 Function を Function1 のエイリアスと定義しています。 &br() &br() &aname(12.3.4,option=nolink){ } *** 12.3.4 クラス Array (Class Array) ジェネリックな配列クラスは、次のように与えられています。 final class Array[A](len: Int) extends Seq[A] { def length: Int = len def apply(i: Int): A = ... def update(i: Int, x: A): Unit = ... def elements: Iterator[A] = ... def subArray(from: Int, end: Int): Array[A] = ... def filter(p: A => Boolean): Array[A] = ... def map[B](f: A => B): Array[B] = ... def flatMap[B](f: A => Array[B]): Array[B] = ... } If T is not a type parameter or abstract type, the type Array[T] is represented as the native array type []T in the underlying host system . In that case length returns the length of the array, apply means subscripting, and update means element update . もし T が型パラメータあるいは抽象型でないなら、型 Array[T] は ホストシステム中のネイティブな配列型 []T として表現されます。 そのような場合、length は配列の長さを返し、apply は添え字指定を意味し、 update は要素の更新を意味します。 Because of the syntactic sugar for apply and update operations (§6.26), we have the following correspondences between Scala and Java/C# code for operations on an array xs: apply と update 操作 (&link_anchor(6.26,page=Spec2.8Chap6d){§6.26}) の糖衣構文のおかげで、配列 xs の操作について、 Scala と Java/C# のコード間に次の対応があります。: Scala Java/C# xs.length xs.length xs(i) xs[i] xs(i) = e xs[i] = e Arrays also implement the sequence trait scala.Seq by defining an elements method which returns all elements of the array in an Iterator . 配列は、イテレータ中の配列のすべての要素を返す elements メソッドを定義することで、シーケンストレイト scala.Seq も実装しています。 Because of the tension between parametrized types in Scala and the ad-hoc implementation of arrays in the host-languages, some subtle points need to be taken into account when dealing with arrays . These are explained in the following . Scala におけるパラメータ化された型と、 ホスト言語における配列のアドホックな実装間の緊張関係のため、 配列を取り扱うとき、いくつかの微妙な点を考慮する必要があります。 それらを次に説明します。 First, unlike arrays in Java or C#, arrays in Scala are not co-variant; That is, S <: T does not imply Array[S] <: Array[T] in Scala . However, it is possible to cast an array of S to an array of T if such a cast is permitted in the host environment . For instance Array[String] does not conform to Array[Object], even though String conforms to Object . However, it is possible to cast an expression of type Array[String] to Array[Object], and this cast will succeed without raising a ClassCastException . 最初に、Java あるいは C# 中の配列と異なり、Scala 中の配列は共変&strong(){ではありません}。;すなわち、Scalaでは、 S <: T が Array[S] <: Array[T] を意味しません。 しかし、S の配列をキャストして T の配列にすることは、 もしそのようなキャストがホスト環境で許されるなら、可能です。 たとえば、String は Objectに適合しますが、インスタンス Array[String] は Array[Object] に適合しません。 しかし、型 Array[String] の式を型 Array[Object] へキャストすることは可能であり、このキャストは ClassCastException を引き起こすことなく成功します。 例: val xs = new Array[String](2) // val ys: Array[Object] = xs // **** error: 非互換な型 val ys: Array[Object] = xs.asInstanceOf[Array[Object]] // OK Second, for polymorphic arrays, that have a type parameter or abstract type T as their element type, a representation different from []T might be used. However, it is guaranteed that isInstanceOf and asInstanceOf still work as if the array used the standard representation of monomorphic arrays: 第二に、その要素型として型パラメータあるいは抽象型 T を持つ &strong(){多相的配列}に対して、[]T と異なる表現が使われることがあります。 しかし、isInstanceOf と asInstanceOf があたかも配列が単相的配列の標準的な表現を使うかのように、 それでも動作することは保証されています。: val ss = new Array[String](2) def f[T](xs: Array[T]): Array[String] = if (xs.isInstanceOf[Array[String]]) xs.asInstanceOf[Array[String]) else throw new Error("not an instance") f(ss) // ss を返す The representation chosen for polymorphic arrays also guarantees that polymorphic array creations work as expected . An example is the following implementation of method mkArray, which creates an array of an arbitrary type T , given a sequence of T's which defines its elements . 多相的配列用に選ばれた表現は、 多相的配列の生成が期待どおり動作することも保証しています。 次の例はメソッド mkArray の実装で、その要素を定義する T のシーケンスを与えられ、任意の型 T の配列を生成します。 def mkArray[T](elems: Seq[T]): Array[T] = { val result = new Array[T](elems.length) var i = 0 for (elem <- elems) { result(i) = elem i += 1 } } Note that under Java's erasure model of arrays the method above would not work as expected - in fact it would always return an array of Object . Java の配列の型消去モデルの下では、上のメソッドが期待通りには動作しない --- 実際、それは常に Object の配列を返す --- ことに注意してください。 Third, in a Java environment there is a method System.arraycopy which takes two objects as parameters together with start indices and a length argument, and copies elements from one object to the other, provided the objects are arrays of compatible element types . System.arraycopy will not work for Scala's polymorphic arrays because of their different representation . One should instead use method Array.copy which is defined in the companion object of class Array . This companion object also defines various constructor methods for arrays, as well as the extractor method unapplySeq (§8.1.8) which enables pattern matching over arrays . 第三に、Java 環境ではメソッド System.arraycopy があります。それは、 2 つのオブジェクトをパラメータにとると共に、開始インデックスと長さの引数を もち、オブジェクトは互換の要素型からなる配列であるとして、 1 つのオブジェクトから他方へ要素をコピーします (訳注:arraycopy(Object src, int srcPos, Object dest, int destPos, int length) )。 System.arraycopy は、Scala の多相的配列に対しては機能しません。 なぜなら、それらの表現が異なるからです。 その代わりに Array.copy を使うべきです。 それはクラス Array のコンパニオンオブジェクト中で定義されています。 このコンパニオンオブジェクトも、 配列上のパターンマッチングを可能にする抽出子メソッド unapplySeq (&link_anchor(8.1.8,page=Spec2.8Chap8a){§8.1.8})と同様、 配列のために種々のコンストラクタメソッドを定義しています。 package scala object Array { /** copies array elements from 'src' to 'dest'. */ /** 'src' から 'dest'へ配列要素をコピー */ def copy(src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int): Unit = ... /** Concatenate all argument arrays into a single array. */ /** 1 つの配列へ、すべての引数配列を連結 */ def concat[T](xs: Array[T]*): Array[T] = ... /** Create a an array of successive integers. */ /** 連続した整数からなる配列を生成 */ def range(start: Int, end: Int): Array[Int] = ... /** Create an array with given elements. */ /** 与えられた要素の配列を生成 */ def apply[A <: AnyRef](xs: A*): Array[A] = ... /** Analogous to above. */ def apply(xs: Boolean*): Array[Boolean] = ... def apply(xs: Byte*) : Array[Byte] = ... def apply(xs: Short*) : Array[Short] = ... def apply(xs: Char*) : Array[Char] = ... def apply(xs: Int*) : Array[Int] = ... def apply(xs: Long*) : Array[Long] = ... def apply(xs: Float*) : Array[Float] = ... def apply(xs: Double*) : Array[Double] = ... def apply(xs: Unit*) : Array[Unit] = ... /** Create an array containing several copies of an element. */ /** 要素の複数のコピーを含む配列の生成 */ def make[A](n: Int, elem: A): Array[A] = { /** Enables pattern matching over arrays */ /** 配列上のパターンマッチングを可能とする */ def unapplySeq[A](x: Array[A]): Option[Seq[A]] = Some(x) } &br() &bold(){Example 12.3.1} 次のメソッドは、与えられた引数配列を複写し、 オリジナルと複写したものからなる、ペアを返します: def duplicate[T](xs: Array[T]) = { val ys = new Array[T](xs.length) Array.copy(xs, 0, ys, 0, xs.length) (xs, ys) } &br() &br() &aname(12.4,option=nolink){ } ** 12.4 クラス Node (Class Node) package scala.xml trait Node { /** the label of this node */ /** このノードのラベル */ def label: String /** attribute axis */ /** axis 属性 */ def attribute: Map[String, String] /** child axis (all children of this node) */ /** 子 axis (このノードの全ての子) */ def child: Seq[Node] /** descendant axis (all descendants of this node) */ /** 子孫 axis (このノードの全ての子孫) */ def descendant: Seq[Node] = child.toList.flatMap { x => x::x.descendant.asInstanceOf[List[Node]] } /** descendant axis (all descendants of this node) */ /** 子孫 axis (このノードの全ての子孫) */ def descendant_or_self: Seq[Node] = this::child.toList.flatMap { x => x::x.descendant.asInstanceOf[List[Node]] } override def equals(x: Any): Boolean = x match { case that:Node => that.label == this.label && that.attribute.sameElements(this.attribute) && that.child.sameElements(this.child) case _ => false } /** XPath style projection function. Returns all children of this node * that are labeled with 'that'. The document order is preserved. */ /** XPath スタイルの射影関(projection function)数。'that'と印された、 * このノードの全ての子を返す。ドキュメントの順番は維持される。 */ def \(that: Symbol): NodeSeq = { new NodeSeq({ that.name match { case "_" => child.toList case _ => var res:List[Node] = Nil for (x <- child.elements if x.label == that.name) { res = x::res } res.reverse } }) } /** XPath style projection function. Returns all nodes labeled with the * name 'that' from the 'descendant_or_self' axis. * Document order is preserved. */ /** XPath スタイルの射影関数。'descendat_or_self'(子孫または自身) axis * から、'that'と印されたこのノードの全ての子を返す。 * ドキュメントの順番は維持される。 */ def \\(that: Symbol): NodeSeq = { new NodeSeq( that.name match { case "_" => this.descendant_or_self case _ => this.descendant_or_self.asInstanceOf[List[Node]]. filter(x => x.label == that.name) }) } /** hashcode for this XML node */ /** この XML ノードに対する ハッシュコード */ override def hashCode = Utility.hashCode(label, attribute.toList.hashCode, child) /** string representation of this node */ /** このノードの文字列表現 */ override def toString = Utility.toXML(this) } &br() &br() &aname(12.5,option=nolink){ } ** 12.5 事前定義済みオブジェクト (The Predef Object) The predef object defines standard functions and type aliases for Scala programs . It is always implicitly imported, so that all its defined members are available without qualification . Its definition for the JVM environment conforms to the following signature: 事前定義済みオブジェクトは Scala プログラムの標準関数と型エイリアスを定義します。 これは常に暗黙のうちにインポートされるので、 その定義されたすべてのメンバーは修飾なしで利用可能です。 JVM 環境での定義は、次のシグニチャに一致します: package scala object Predef { // classOf ------------------------------------------------------- /** Returns the runtime representation of a class type. */ /** クラス型の実行時表現を返す */ def classOf[T]: Class[T] = null // this is a dummy, classOf is handled by compiler. // これはダミー。 classOf はコンパイラによって処理される。 // 標準の型エイリアス ------------------------------------------- type byte = scala.Byte type short = scala.Short type char = scala.Char type int = scala.Int type long = scala.Long type float = scala.Float type double = scala.Double type boolean = scala.Boolean type unit = scala.Unit type String = java.lang.String type Class[T] = java.lang.Class[T] type Runnable = java.lang.Runnable type Throwable = java.lang.Throwable type Exception = java.lang.Exception type Error = java.lang.Error type RuntimeException = java.lang.RuntimeException type NullPointerException = java.lang.NullPointerException type ClassCastException = java.lang.ClassCastException type IndexOutOfBoundsException = java.lang.IndexOutOfBoundsException type ArrayIndexOutOfBoundsException = java.lang.ArrayIndexOutOfBoundsException type StringIndexOutOfBoundsException = java.lang.StringIndexOutOfBoundsException type UnsupportedOperationException = java.lang.UnsupportedOperationException type IllegalArgumentException = java.lang.IllegalArgumentException type NoSuchElementException = java.util.NoSuchElementException type NumberFormatException = java.lang.NumberFormatException // その他 ----------------------------------------------------- type Function[-A, +B] = Function1[A, B] type Map[A, B] = collection.immutable.Map[A, B] type Set[A] = collection.immutable.Set[A] val Map = collection.immutable.Map val Set = collection.immutable.Set // エラーとアサーション-------------------------------------------- def error(message: String): Nothing = throw new Error(message) def exit: Nothing = exit(0) def exit(status: Int): Nothing = { java.lang.System.exit(status) throw new Throwable() } def assert(assertion: Boolean) { if (!assertion) throw new java.lang.AssertionError("assertion failed") } def assert(assertion: Boolean, message: Any) { if (!assertion) throw new java.lang.AssertionError("assertion failed: " + message) } def assume(assumption: Boolean) { if (!assumption) throw new IllegalArgumentException("assumption failed") } def assume(assumption: Boolean, message: Any) { if (!assumption) throw new IllegalArgumentException(message.toString) } // tupling --------------------------------------------------------- type Pair[+A, +B] = Tuple2[A, B] object Pair { def apply[A, B](x: A, y: B) = Tuple2(x, y) def unapply[A, B](x: Tuple2[A, B]): Option[Tuple2[A, B]] = Some(x) } type Triple[+A, +B, +C] = Tuple3[A, B, C] object Triple { def apply[A, B, C](x: A, y: B, z: C) = Tuple3(x, y, z) def unapply[A, B, C](x:Tuple3[A, B, C]): Option[Tuple3[A, B, C]] = Some(x) } class ArrowAssoc[A](x: A) { def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y) } implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x) // 印字と読み込み ----------------------------------------------- def print(x: Any) = Console.print(x) def println() = Console.println() def println(x: Any) = Console.println(x) def printf(text: String, xs: Any*) = Console.printf(text, xs: _*) def format(text: String, xs: Any*) = Console.format(text, xs: _*) def readLine(): String = Console.readLine() def readLine(text: String, args: Any*) = Console.readLine(text, args) def readBoolean() = Console.readBoolean() def readByte() = Console.readByte() def readShort() = Console.readShort() def readChar() = Console.readChar() def readInt() = Console.readInt() def readLong() = Console.readLong() def readFloat() = Console.readFloat() def readDouble() = Console.readDouble() def readf(format: String) = Console.readf(format) def readf1(format: String) = Console.readf1(format) def readf2(format: String) = Console.readf2(format) def readf3(format: String) = Console.readf3(format) // The ''catch-all'' implicit ---------------------------------------- implicit def identity[A](x: A): A = x // クラス Ordered へのビュー %% @@@KSW what is ''Proxy''? It's not defined anywhere. %% @@@MO It's a Java interface. implicit def int2ordered(x: Int):Ordered[Int] = new Ordered[Int] with Proxy{ def self: Any = x def compare[B >: Int <% Ordered[B]](y: B): Int = y match { case y1: Int => if (x < y1) -1 else if (x > y1) 1 else 0 case _ => -(y compare x) } } // The implementations of following methods are analogous to the last one: // 次のメソッドの実装は、最後の一つに類似 implicit def char2ordered(x: Char): Ordered[Char] = ... implicit def long2ordered(x: Long): Ordered[Long] = ... implicit def float2ordered(x: Float): Ordered[Float] = ... implicit def double2ordered(x: Double): Ordered[Double] = ... implicit def boolean2ordered(x: Boolean): Ordered[Boolean] = ... implicit def seq2ordered[A <% Ordered[A]](xs: Array[A]): Ordered[Seq[A]] = new Ordered[Seq[A]] with Proxy { def compare[B >: Seq[A] <% Ordered[B]](that: B): Int = that match { case that: Seq[A] => var res = 0 val these = this.elements val those = that.elements while (res == 0 && these.hasNext) res = if (!those.hasNext) 1 else these.next compare those.next case _ => - (that compare xs) } implicit def string2ordered(x: String): Ordered[String] = new Ordered[String] with Proxy { def self: Any = x def compare[b >: String <% Ordered[b]](y: b): Int = y match { case y1: String => x compare y1 case _ => -(y compare x) } } implicit def tuple2ordered[a1 <% Ordered[a1], a2 <% Ordered[a2]] (x: Tuple2[a1, a2]): Ordered[Tuple2[a1, a2]] = new Ordered[Tuple2[a1, a2]] with Proxy { def self: Any = x def compare[T >: Tuple2[a1, a2] <% Ordered[T]](y: T): Int = y match { case y: Tuple2[a1, a2] => val res = x._1 compare y._1 if (res == 0) x._2 compare y._2 else res case _ => -(y compare x) } } // Tuple3 ~ Tuple9 についても同様 // クラス Seq へのビュー implicit def string2seq(str: String): Seq[Char] = new Seq[Char] { def length = str.length() def elements = Iterator.fromString(str) def apply(n: Int) = str.charAt(n) override def hashCode: Int = str.hashCode override def equals(y: Any): Boolean = (str == y) override protected def stringPrefix: String = "String" } // プリミティブ型から Java のボックス型へのビュー implicit def byte2Byte(x: Byte) = new java.lang.Byte(x) implicit def short2Short(x: Short) = new java.lang.Short(x) implicit def char2Character(x: Char) = new java.lang.Character(x) implicit def int2Integer(x: Int) = new java.lang.Integer(x) implicit def long2Long(x: Long) = new java.lang.Long(x) implicit def float2Float(x: Float) = new java.lang.Float(x) implicit def double2Double(x: Double) = new java.lang.Double(x) implicit def boolean2Boolean(x: Boolean) = new java.lang.Boolean(x) // 数値変換ビュー implicit def byte2short(x: Byte): Short = x.toShort implicit def byte2int(x: Byte): Int = x.toInt implicit def byte2long(x: Byte): Long = x.toLong implicit def byte2float(x: Byte): Float = x.toFloat implicit def byte2double(x: Byte): Double = x.toDouble implicit def short2int(x: Short): Int = x.toInt implicit def short2long(x: Short): Long = x.toLong implicit def short2float(x: Short): Float = x.toFloat implicit def short2double(x: Short): Double = x.toDouble implicit def char2int(x: Char): Int = x.toInt implicit def char2long(x: Char): Long = x.toLong implicit def char2float(x: Char): Float = x.toFloat implicit def char2double(x: Char): Double = x.toDouble implicit def int2long(x: Int): Long = x.toLong implicit def int2float(x: Int): Float = x.toFloat implicit def int2double(x: Int): Double = x.toDouble implicit def long2float(x: Long): Float = x.toFloat implicit def long2double(x: Long): Double = x.toDouble implicit def float2double(x: Float): Double = x.toDouble } &br() &br() &aname(bibliography,option=nolink){ } ** Bibliography [Dra10] Iulian Dragos. Scala specialization, 2010. SID-9. [KP07] Andrew J. Kennedy and Benjamin C. Pierce. On Decidability of Nominal Subtyping with Variance, January 2007. FOOL-WOOD '07. [Oa04] Martin Odersky and al. An Overview of the Scala Programming Language . Technical Report IC/2004/64, EPFL Lausanne, Switzerland, 2004. [OCRZ03] Martin Odersky, Vincent Cremet, Christine Rockl, and Matthias Zenger. A Nominal Theory of Objects with Dependent Types. In Proc. ECOOP'03, Springer LNCS, July 2003. [Ode06] Martin Odersky. The Scala Experiment - Can We Provide Better Language Support for Component Systems? In Proc. ACM Symposium on Principles of Programming Languages, 2006. [OZ05a] Martin Odersky and Matthias Zenger. Independently Extensible Solutions to the Expression Problem. In Proc. FOOL 12, January 2005. &nolink(http://homepages.inf.ed.ac.uk/wadler/fool) . [OZ05b] Martin Odersky and Matthias Zenger. Scalable Component Abstractions. In Proc. OOPSLA, 2005. [W3C] W3C. Extensible Markup Language (XML). &nolink(http://www.w3.org/TR/REC-xml) . #center(){[[前>Spec2.8Chap12a]] [[目次>Spec2.8和訳]] [[次:ChapA>Spec2.8ChapAa]]}

表示オプション

横に並べて表示:
変化行の前後のみ表示:
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。