How to write a polymorphic input function in Scala?

I am trying to write some convenient functions in Scala for reading in arrays of values.

I started with a function that converts a string like "1 1 2 3 5 8" into an [Int] array:

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

This works fine, except if I want to read not only ints, but also Longs or BigInts or Doubles, I need to define a function for each one that seems wasteful (especially if I generalize to reading in matrices or other composite data )

I would like to write one polymorphic function as follows:

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

As far as I understand, this is not possible because the String class does not have a polymorphic "to" method. Good; Instead, I will try to define it as a helper method:

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

It looks like I need to conditionally define a method for a type parameter - if A is Int, then call in.toInt ; if A is Double, call in.toDouble ; if A is Tuple2 [Int, Int], call the helper method toTupleOfInts(in) . As far as I know, this is also impossible.

In another functional language that I know of, Haskell, this problem is handled by the Read class, which defines the polymorphic read function, which converts from a string to the desired data type.

What is the idiomatic way to do this (i.e. write polymorphic input functions) in Scala?

+4
source share
1 answer

You can do something very close to the Haskell class. However, it cannot be obtained automatically (at least, perhaps, the macro will allow this in some future version)

First, define an attribute equivalent to the type class.

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

Then make some instance implicitly accessible, preferably in a companion object

 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]) ... } 

Finally, define a method that simplifies access to Read

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

You can invoke a read of any type for which there is an Read instance in the implicit scope.

+9
source

All Articles