只要你需要自己創建這些類型,它並沒有給你太多。但是,只要你讓編譯器爲你做的東西,它會更有用。
我顯示此之前,讓我們改變表示皮亞諾aritmetic弄成短的一個辦法:
sealed abstract class List[+H, N <: Num](val size: N) {
def ::[T >: H](value: T): List[T, Succ[N]] = Cons(value, this)
}
case object Nil extends List[Nothing, Zero.type](Zero)
case class Cons[+H, N <: Num](head: H, tail: List[H, N]) extends List[H, Succ[N]](Succ(tail.size))
type ::[+H, N <: Num] = Cons[H, N]
如果您:
sealed trait Num
case object Zero extends Num
case class Succ[N <: Num](num: N) extends Num
然後,您可以在編譯時已知的尺寸創建列表檢查用sych list創建的類型,它的尺寸將在其類型中編碼:
val list = 1 :: 2 :: 3 :: 4 :: Nil // List[Int, Succ[Succ[Succ[Succ[Zero.type]]]]] = Cons(1,Cons(2,Cons(3,Cons(4,Nil))))
你可以嘗試做的下一件事是使用implicits來檢查某些東西,例如
trait EvenNum[N <: Num]
implicit val zeroIsEven = new EvenNum[Zero.type] {}
implicit def evenNPlusTwo[N <: Num](implicit evenN: EvenNum[N]) = new EvenNum[Succ[Succ[N]]] {}
有了,你可以強制執行時隱證據可以提供一些操作只能做到:
def operationForEvenSizeList[T, N <: Num](list: List[T, N])(implicit ev: EvenNum[N]) = {
// do something with list of even length
}
operationForEvenSizeList(1 :: 2 :: Nil) // ok
operationForEvenSizeList(1 :: 2 :: 3 :: Nil) // compiler error
至於我可以告訴類型級編程的真正力量在斯卡拉出現時你開始使用implicits來創建新的類型:你可以使用隱式證據,類型類派生和一些結構樣板的移除。
一個對泛型編程有很大幫助的庫是無形的。我相信,一旦你做了一兩次運動練習或者帶有暗示的類型派生練習,對你來說這將是一件有趣的事情。
回到你的代碼:你可以提供一些暗示,它會爲你生成和提供你的類的實例。此外,除了創建新類外,此代碼還會執行其他操作,例如組合您將添加到這些類中的元素列表,或者提供從PeanoNumType到Int的轉換,或者添加一些在編譯時工作的謂詞等。天空是極限。