I'm trying to write some convenience 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" to an Array[Int]:
def readInts(in: String) = in.split(" ").map(_.toInt)
This works fine, except that if I want to read not just Ints but Longs or BigInts or Doubles, I need to define a function for each one, which seems wasteful (especially if I generalize to reading in matrices or other compound data)
I'd like to be able to write a single polymorphic function as follows:
def readArray[A](in: String) = in.split(" ").map(_.to[A])
As far as I understand, this is impossible because the String class doesn't have a polymorphic 'to' method. Alright; I'll try to define it as a helper method instead:
def to[A](in: String) = ???
It seems like I need to define the method conditionally on the type parameter - if A is Int, then call in.toInt
; if A is Double, call in.toDouble
; if A is Tuple2[Int,Int], call a helper method toTupleOfInts(in)
. As far as I know, this is also impossible.
In the other functional language I know, Haskell, this problem is handled by the 'Read' typeclass, which defines a polymorphic function 'read' that converts from a String to the desired data type.
What is an idiomatic way to do this (i.e. write polymorphic input functions) in Scala?
You can do something very close to Haskell typeclasses. However, it cannot be derived automatically (at least yet, maybe macro will allow that in some future version)
First, define a trait, equivalent to the typeclass.
trait Read[A] {
def read(in: String): A
}
Then make some instance implicitly available, preferably in the 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 makes the Read
easily accessible
def read[A](in: String[A])(implicit reader: Read[A]) = reader.read(in)
You may call read on any type for which there is a Read instance in implicit scope.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With