2017-09-12 4 views
4

Nous pouvons créer un type littéral via informes:Récupère le type d'un "type singleton"

import shapeless.syntax.singleton._ 
var x = 42.narrow 
// x: Int(42) = 42 

Mais comment puis-je utiliser avec Int(42) comme un type s'il est encore impossible de créer alias de type

type Answ = Int(42) // won't compile 
// or 
def doSmth(value: Int(42)) = ... // won't compile 

Répondre

5

1) En Typelevel Scala vous pouvez écrire juste

val x: 42 = 42 

type Answ = 42 

def doSmth(value: 42) = ??? 

2) Dans Dotty Sca Vous pouvez écrire la même chose.

3) Dans Lightbend Scala (c.-à-norme Scala) + Shapeless vous pouvez écrire

import shapeless.Witness 
import shapeless.syntax.singleton._ 

val x: Witness.`42`.T = 42.narrow 

type Answ = Witness.`42`.T 

def doSmth(value: Witness.`42`.T) = ??? 

Dans le cas 1) build.sbt doit être

scalaOrganization := "org.typelevel" 
scalaVersion := "2.12.3-bin-typelevel-4" 
scalacOptions += "-Yliteral-types" 

Dans le cas 2) build.sbt devrait être

scalaOrganization := "ch.epfl.lamp" 
scalaVersion := "0.3.0-RC2" 

et plugins.sbt

addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.1.5") 

Dans le cas 3) build.sbt devrait être

scalaOrganization := "org.scala-lang" 
scalaVersion := "2.12.3" 
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.2" 

4) ou vous pouvez utiliser Typelevel Scala et Shapeless en même temps.

1

Int(42) n'est pas une syntaxe Scala valide pour le type.

Les types singleton IIRC ont été implémentés dans scalac pendant un certain temps, mais les programmeurs n'avaient aucune syntaxe pour les définir. Shapeless fournit cela, avec des macros, ainsi que des machines supplémentaires.

En particulier, shapeless.Witness est un objet qui contient à la fois des informations de type et la valeur associée, et peut également être invoqué à partir de l'un ou l'autre.

import shapeless.Witness 
import shapeless.syntax.singleton._ 
import shapeless.test.illTyped // test string for causing type-errors when compiled 

// --- Type aliases --- 
val w = 42.witness 
type Answ1 = w.T // that is your Int(42) singleton type 
type Answ2 = Witness.`42`.T // same, but without extra variable 
implicitly[Answ1 =:= Answ2] // compiles, types are the same 

// --- Value definitions --- 
val a: Answ1 = 42 // compiles, value OK, and no need to `narrow` 
illTyped { "val b: Answ1 = 43" } // would not compile 
val c: Witness.`43`.T = 43 // that syntax is OK here too 

// --- Summoning values --- 
val answ = Witness[Answ1].value // will not compile for non-singleton 
def genericSingletonMethod[A](implicit W: Witness.Aux[A]) = s"Summoning ${W.value}" 
assert { genericSingletonMethod[Answ1] == "Summoning 42" } 
assert { genericSingletonMethod[Witness.`"string"`.T] == "Summoning string" }