Scala Language
Programmation au niveau du type
Recherche…
Introduction à la programmation au niveau du type
Si nous considérons une liste hétérogène, dans laquelle les éléments de la liste ont des types variés mais connus, il peut être souhaitable de pouvoir effectuer des opérations sur les éléments de la liste collectivement sans ignorer les informations de type des éléments. L'exemple suivant implémente une opération de mappage sur une liste hétérogène simple.
Comme le type d'élément varie, la classe d'opérations que nous pouvons effectuer est restreinte à une forme de projection de type. Nous définissons donc un trait Projection
type Apply[A]
abstrait type Apply[A]
calculant le type de résultat de la projection et def apply[A](a: A): Apply[A]
calculant la valeur de résultat de la projection.
trait Projection {
type Apply[A] // <: Any
def apply[A](a: A): Apply[A]
}
En implémentant le type Apply[A]
nous programmons au niveau du type (par opposition au niveau de la valeur).
Notre type de liste hétérogène définit une opération de map
paramétrée par la projection souhaitée ainsi que par le type de projection. Le résultat de l'opération de carte est abstrait, variera selon la classe et la projection, et doit toujours être une liste HList
:
sealed trait HList {
type Map[P <: Projection] <: HList
def map[P <: Projection](p: P): Map[P]
}
Dans le cas de HNil
, la liste hétérogène vide, le résultat de toute projection sera toujours lui-même. Ici, nous déclarons le trait HNil
comme une commodité afin que nous puissions écrire HNil
comme un type au lieu de HNil.type
:
sealed trait HNil extends HList
case object HNil extends HNil {
type Map[P <: Projection] = HNil
def map[P <: Projection](p: P): Map[P] = HNil
}
HCons
sont la liste hétérogène non vide. Ici, nous affirmons que lorsqu’on applique une opération de carte, le type de tête résultant est celui qui résulte de l’application de la projection à la valeur de tête ( P#Apply[H]
) et que le type de queue résultant projection sur la queue ( T#Map[P]
), connue pour être une HList
:
case class HCons[H, T <: HList](head: H, tail: T) extends HList {
type Map[P <: Projection] = HCons[P#Apply[H], T#Map[P]]
def map[P <: Projection](p: P): Map[P] = HCons(p.apply(head), tail.map(p))
}
La projection la plus évidente consiste à exécuter une opération d’emballage - l’exemple suivant fournit une instance de HCons[Option[String], HCons[Option[Int], HNil]]
:
HCons("1", HCons(2, HNil)).map(new Projection {
type Apply[A] = Option[A]
def apply[A](a: A): Apply[A] = Some(a)
})