2017-05-13 66 views
3

我想深入瞭解Scala中的類型級編程,並開始做一些小練習。我開始在類型級別實現Peano號碼。以下是下面的代碼!Scala中的類型級別編程

sealed trait PeanoNumType { // Type at the end indicates to the reader that we are dealing with types 
    type plus[That <: PeanoNumType] <: PeanoNumType 
} 

sealed trait ZeroType extends PeanoNumType { 
    type plus[That <: PeanoNumType] = That 
} 

sealed trait NextType[This <: PeanoNumType] extends PeanoNumType { 
    type plus[That <: PeanoNumType] = NextType[This#plus[That]] 
} 

現在問題是,上面的實現會給我買什麼?我怎樣才能使用它?

回答

6

只要你需要自己創建這些類型,它並沒有給你太多。但是,只要你讓編譯器爲你做的東西,它會更有用。

我顯示此之前,讓我們改變表示皮亞諾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的轉換,或者添加一些在編譯時工作的謂詞等。天空是極限。