Scala Language
Programnivå på typnivå
Sök…
Introduktion till typnivåprogrammering
Om vi betraktar en heterogen lista, där elementen i listan har olika men kända typer, kan det vara önskvärt att kunna utföra operationer på listans element kollektivt utan att kassera elementens typinformation. Följande exempel implementerar en mappningsoperation över en enkel heterogen lista.
Eftersom elementtypen varierar, är den klass av operationer vi kan utföra begränsad till någon form av typ projektion, så vi definierar en egenskap Projection
med abstrakt type Apply[A]
att beräkna resultattypen hos utsprånget, och def apply[A](a: A): Apply[A]
beräkna resultatvärdet av utsprånget.
trait Projection {
type Apply[A] // <: Any
def apply[A](a: A): Apply[A]
}
Vid implementering av type Apply[A]
programmerar vi på typnivå (i motsats till värdenivån).
Vår heterogena listtyp definierar en map
operation parametriseras av den önskade projektionen liksom projektion typ. Resultatet av kartoperationen är abstrakt, kommer att variera genom att implementera klass och projektion och måste naturligtvis fortfarande vara en HList
:
sealed trait HList {
type Map[P <: Projection] <: HList
def map[P <: Projection](p: P): Map[P]
}
När det gäller HNil
, den tomma heterogena listan, kommer resultatet av alla projektioner alltid att vara sig själv. Här förklarar vi trait HNil
som en bekvämlighet så att vi kan skriva HNil
som en typ i stället för 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
är den icke-tomma heterogena listan. Här hävdar vi att vid tillämpning av en kartoperation är den resulterande huvudtypen den som är resultatet av tillämpningen av projektionen på huvudvärdet ( P#Apply[H]
), och att den resulterande svanstypen är den som är resultatet av kartläggning av projektion över svansen ( T#Map[P]
), som är känd för att vara en 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))
}
Det mest uppenbara sådana projektet är att utföra någon form av lindningsoperation - följande exempel ger en instans av 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)
})