4

値の配列を読み取るために、Scalaでいくつかの便利な関数を書き込もうとしています。

「112 358」のような文字列をArray[Int]に変換する関数から始めました。

def readInts(in: String) = in.split(" ").map(_.toInt)

これは問題なく機能しますが、Intだけでなく、Longs、BigInts、Doublesも読み取りたい場合は、それぞれに関数を定義する必要があります。これは無駄に思えます(特に、行列やその他の複合データの読み取りに一般化する場合)。

次のように単一のポリモーフィック関数を記述できるようにしたいと思います。

def readArray[A](in: String) = in.split(" ").map(_.to[A])

私が理解している限り、Stringクラスにはポリモーフィックな'to'メソッドがないため、これは不可能です。大丈夫; 代わりに、ヘルパーメソッドとして定義してみます。

def to[A](in: String) = ???

タイプパラメータで条件付きでメソッドを定義する必要があるようです。AがIntの場合は、in.toInt;を呼び出します。AがDoubleの場合、in.toDouble;を呼び出します。AがTuple2[Int、Int]の場合、ヘルパーメソッドを呼び出しますtoTupleOfInts(in)。私の知る限り、これも不可能です。

私が知っている他の関数型言語であるHaskellでは、この問題は「Read」型クラスによって処理されます。これは、文字列から目的のデータ型に変換するポリモーフィック関数「read」を定義します。

Scalaでこれを行う(つまり、多態的な入力関数を書く)慣用的な方法は何ですか?

4

1 に答える 1

9

Haskell型クラスに非常に近いことをすることができます。ただし、自動的に導出することはできません(少なくとも、将来のバージョンではマクロで許可される可能性があります)

まず、型クラスと同等の特性を定義します。

trait Read[A] {
  def read(in: String): A
}

次に、できればコンパニオンオブジェクトで、いくつかのインスタンスを暗黙的に使用可能にします

object Read {

  implicit object ReadInt extends Read[Int] {
    def read(in: String): Int = in.toInt
  }

  implicit object ReadDouble ....

  implicit def readArray[A](implicit readItem: Read[A]) : Read[Array[A]]
    = new Read[Array[A]] {
      def read(in: String) = in.split(" ").map(readItem.read _)
    }

   implicit def readTuple[A,B](implicit readA: Read[A], readB: Read[B]) ...

}

Read最後に、簡単にアクセスできるようにするメソッドを定義します

def read[A](in: String[A])(implicit reader: Read[A]) = reader.read(in)

暗黙的なスコープにReadインスタンスが存在する任意のタイプでreadを呼び出すことができます。

于 2012-06-14T19:25:21.327 に答える