We can create a literal types via shapeless:
import shapeless.syntax.singleton._
var x = 42.narrow
// x: Int(42) = 42
But how can I operate with Int(42)
as a type if it's even impossible to create type alias
type Answ = Int(42) // won't compile
// or
def doSmth(value: Int(42)) = ... // won't compile
In Typelevel Scala you can write just
val x: 42 = 42
type Answ = 42
def doSmth(value: 42) = ???
In Dotty Scala you can write the same.
In Lightbend Scala (i.e. standard Scala) + Shapeless you can write
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) = ???
In case 1) build.sbt should be
scalaOrganization := "org.typelevel"
scalaVersion := "2.12.3-bin-typelevel-4"
scalacOptions += "-Yliteral-types"
In case 2) build.sbt should be
scalaOrganization := "ch.epfl.lamp"
scalaVersion := "0.3.0-RC2"
and plugins.sbt
addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.1.5")
In case 3) build.sbt should be
scalaOrganization := "org.scala-lang"
scalaVersion := "2.12.3"
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.2"
Update. Since version 2.13.0 there are literal types in standard Scala
val x: 42 = 42
val x1: 42 = valueOf[42]
type Answ = 42
def doSmth(value: 42) = ???
https://github.com/scala/scala/releases/v2.13.0 (Language changes / Literal types)
Int(42)
is not a valid Scala syntax for type.
IIRC singleton types were implemented in scalac for a while, but programmers had no syntax of defining such. Shapeless provides that, with macros, as well as some extra machinery.
In particular, shapeless.Witness
is an object that contains both type information and associated value, and also can be summoned from either.
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" }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With