Tant que vous avez besoin de créer ces types vous-même, cela ne vous donne pas grand-chose. Mais, dès que vous faites du compilateur faire les choses pour vous, ce sera beaucoup plus utile.
Avant le montrer, nous allons changer une façon de représenter Peano aritmetic en quelque chose de plus court:
sealed trait Num
case object Zero extends Num
case class Succ[N <: Num](num: N) extends Num
Vous pouvez ensuite créer une liste avec une taille connue au moment de la compilation:
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]
Si vous vérifier le type de sth créé avec la liste de sych il aura la taille encodée dans son type:
val list = 1 :: 2 :: 3 :: 4 :: Nil // List[Int, Succ[Succ[Succ[Succ[Zero.type]]]]] = Cons(1,Cons(2,Cons(3,Cons(4,Nil))))
La prochaine chose que vous pourriez faire serait d'utiliser des implicits pour vérifier quelque chose, par ex.
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]]] {}
Avec cela, vous pouvez appliquer que certaines opérations ne pouvait se faire lorsque la preuve implicite pourrait fournir:
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
Pour autant que je peux dire vrai pouvoir de programmation au niveau du type à Scala apparaît lorsque vous commencez à utiliser des implicits pour créer de nouveaux types: ceux que vous pourriez utiliser pour la preuve implicite, la dérivation de classe de type et la suppression de certains éléments structurels.
Une bibliothèque qui aide beaucoup avec la programmation générique est Shapeless. Je crois que ce sera une chose amusante pour vous de travailler avec, une fois que vous ferez un exercice ou deux avec une dérivation de type classe avec implicits. Retour à votre code: vous pourriez fournir quelques implicits qui généreraient et fourniraient des instances de votre classe pour vous. De plus, en plus de créer une nouvelle classe, ce code ferait aussi quelque chose d'autre, par ex. combinez des listes d'éléments que vous ajouteriez dans ces classes, ou fournissez la conversion de PeanoNumType en Int, ou ajoutez quelques prédicats fonctionnant dans la compilation, etc. Sky est la limite.