2012-06-14 39 views
4

我想在Scala中編寫一些便利函數來讀取值的數組。如何在Scala中編寫多態輸入函數?

我開始,像「1 1 2 3 5 8」的字符串轉換成一個數組[INT]功能:

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

這工作得很好,但如果我想讀不只是INTS但長或BigInts或雙打,我需要爲每一個定義一個函數,這似乎是浪費(尤其是如果我推廣到閱讀矩陣或其他化合物數據)

我想能夠寫一個單一的多態功能如下:

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

據我所知,這是不可能的,因爲String類沒有多態的'to'方法。好的;我會盡力把它定義爲一個輔助方法代替:

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

好像我需要有條件地定義的類型參數的方法 - 如果數據類型爲int,然後調用in.toInt;如果A是雙數,請致電in.toDouble;如果A是Tuple2 [Int,Int],則調用輔助方法toTupleOfInts(in)。據我所知,這也是不可能的。

在我知道的另一個函數式語言Haskell中,這個問題由'Read'類型類處理,它定義了一個多態函數'read',它將字符串轉換爲所需的數據類型。

什麼是在Scala中這樣做(即編寫多態輸入函數)的慣用方法?

+1

你應該使用解析組合器。我還沒有掌握它們,你可以自己做或等待一個完整的答案 – ayvango

+0

你說Haskell的閱讀'從每種數據類型轉換爲一個字符串' - 我認爲你的意思是讀取從字符串轉換爲所需的類型? – overthink

+0

@overthink - 是的,這就是我的意思。感謝您的更正。 –

回答

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實例的類型。