phantom_types



phantom_types

0 0


phantom_types


On Github arnolddevos / phantom_types

Types

Falcon 9

Rocket Software

object RocketWithVals {
  case class Rocket( o: O2, f: Fuel )

  sealed trait O2
  case object NoO2 extends O2
  case object HasO2 extends O2

  sealed trait Fuel
  case object NoFuel extends Fuel
  case object Fueled extends Fuel

  def createRocket() = Rocket(NoO2, NoFuel)       //> createRocket: ()RocketWithVals.Rocket

  def addFuel(x: Rocket) = x match {
    case Rocket(o, NoFuel) => Rocket(o, Fueled)
    case _ => throw new IllegalStateException
  }                                               //> addFuel: (x: RocketWithVals.Rocket)RocketWithVals.Rocket

  def addO2(x: Rocket) = x match {
    case Rocket(NoO2, f) => Rocket(HasO2, f)
    case _ => throw new IllegalStateException
  }                                               //> addO2: (x: RocketWithVals.Rocket)RocketWithVals.Rocket

  def launch(x: Rocket) = x match {
    case Rocket(HasO2, Fueled) => "launched!"
    case _ => throw new IllegalStateException
  }                                               //> launch: (x: RocketWithVals.Rocket)String

  val goodSeq = launch(addO2(addFuel(createRocket)))
                                                  //> goodSeq  : String = launched!

  val anotherGoodSeq = launch(addFuel(addO2(createRocket)))
                                                  //> anotherGoodSeq  : String = launched!


  // val badSeq = launch(addFuel(createRocket()))

  // val anotherBadSeq = launch(addFuel(addO2(addFuel(createRocket()))))
}

Elon does not like the exceptions.

Found http://james-iry.blogspot.com.au

Better Rocket Software

object RocketWithTypes {
  case class Rocket[ O <: O2, F <: Fuel ]()

  sealed trait O2
  trait NoO2 extends O2
  trait HasO2 extends O2

  sealed trait Fuel
  trait NoFuel extends Fuel
  trait Fueled extends Fuel

  def createRocket() = Rocket[NoO2, NoFuel]       //> createRocket: ()RocketWithTypes.Rocket[RocketWithTypes.NoO2,RocketWithTypes.
                                                  //| NoFuel]

  def addFuel[O <: O2](x: Rocket[O, NoFuel]) = Rocket[O, Fueled]
                                                  //> addFuel: [O <: RocketWithTypes.O2](x: RocketWithTypes.Rocket[O,RocketWithTyp
                                                  //| es.NoFuel])RocketWithTypes.Rocket[O,RocketWithTypes.Fueled]

  def addO2[F <: Fuel](x: Rocket[NoO2, F]) = Rocket[HasO2, F]
                                                  //> addO2: [F <: RocketWithTypes.Fuel](x: RocketWithTypes.Rocket[RocketWithTypes
                                                  //| .NoO2,F])RocketWithTypes.Rocket[RocketWithTypes.HasO2,F]

  def launch(x: Rocket[HasO2, Fueled]) = "launched!"
                                                  //> launch: (x: RocketWithTypes.Rocket[RocketWithTypes.HasO2,RocketWithTypes.Fue
                                                  //| led])String

  val goodSeq = launch(addO2(addFuel(createRocket)))
                                                  //> goodSeq  : String = launched!

  val anotherGoodSeq = launch(addFuel(addO2(createRocket)))
                                                  //> anotherGoodSeq  : String = launched!

  // val badSeq = launch(addFuel(createRocket()))

  // val anotherBadSeq = launch(addFuel(addO2(addFuel(createRocket()))))

}

Elon likes the type safety.

Yes, but can I generate JSON with it?

You can!

JSON Parse State as a type (its recursive)

sealed trait JState
trait Start extends JState 
trait Complete extends JState
trait OpenArray[E <: JState] extends JState
trait OpenObject[E <: JState] extends JState

Typesafe JSON Incremental JSON Builder

case class JBuilder[S <: JState]( buffer: B, delimit: B => B) {
  def flip(b: B = empty) = (buffer, JBuilder[S](b, delimit))
  def fullText(implicit bufRep: JSONRep[B]) = bufRep fullText buffer
}

implicit class ArrayOps[E <: JState](b: JBuilder[OpenArray[E]]) {
  def | [T:Element] (t: T) = shift(Element[T] encode t)

  ... 
}

implicit class ObjectOps[E <: JState]( b: JBuilder[OpenObject[E]]) {
  def | [T:Element](f: (String, T)) = shift(f._1, Element[T] encode f._2)

  ...
}

Incremental JSON Generation

object json_generator {
  import au.com.langdale.json.DSL._

  val p1 = JBuilder.start | array | 30.0          //> p1  : au.com.langdale.json.DSL.JBuilder[au.com.langdale.json.DSL.OpenArray[a
                                                  //| u.com.langdale.json.DSL.Complete]] = JBuilder(List(30.0, [),<function1>)

    val p2 = p1 | obj | "name" -> "joe"       //> p2  : au.com.langdale.json.DSL.JBuilder[au.com.langdale.json.DSL.OpenObject[
                                                  //| au.com.langdale.json.DSL.OpenArray[au.com.langdale.json.DSL.Complete]]] = JB
                                                  //| uilder(List("joe", :, "name", {, ,, 30.0, [),<function1>)
    // val p3 = p2 | "element"

    p2.fullText                               //> res0: CharSequence = [30.0,{"name":"joe"

    val p4 = p2 | end | end                   //> p4  : au.com.langdale.json.DSL.JBuilder[au.com.langdale.json.DSL.Complete] =
                                                  //|  JBuilder(List(], }, "joe", :, "name", {, ,, 30.0, [),<function1>)
    p4.fullText                               //> res1: CharSequence = [30.0,{"name":"joe"}]
}