2017-05-13 67 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的转换,或者添加一些在编译时工作的谓词等。天空是极限。