Singletons Literals

Singleton-typed literals

Although Scala's typechecker has always represented singleton types for literal values internally, there has not previously been syntax available to express them, other than by [modifying the compiler][literaltype]. shapeless adds support for singleton-typed literals via implicit macros.

Singleton types bridge the gap between the value level and the type level and hence allow the exploration in Scala of techniques which would typically only be available in languages with support for full-spectrum dependent types. The latest iteration of shapeless records makes a start on that. Another simpler application is the use of Int literals to index into HLists and tuples,

import syntax.std.tuple._

val hlist = 23 :: "foo" :: true :: HNil
hlist(1) should be(res0)

val tuple = (23, "foo", true)
tuple(1) should be(res1)

The examples in the shapeless tests and the following illustrate other possibilities,

import shapeless._, syntax.singleton._
res0.value == 23 should be(true)
res0.value == "foo" should be(true)
val (wTrue, wFalse) = (Witness(true), Witness(false))

type True = wTrue.T
type False = wFalse.T

trait Select[B] { type Out }

implicit val selInt = new Select[True] { type Out = Int }
implicit val selString = new Select[False] { type Out = String }

def select(b: WitnessWith[Select])(t: b.instance.Out) = t

select(true)(23) should be(res0)

//select(true)("foo")
//error: type mismatch;
// found   : String("foo")
// required: Int
//              select(true)("foo")
//                           ^

//select(false)(23)
// error: type mismatch;
//found   : Int(23)
//required: String

select(false)("foo") should be(res1)