/* Some literate Haskell and Scala to demonstrate 1) phantom types 2) I am a masochist 3) ??? 4) profit! The code is probably best viewed with a syntax colorizer for one language or the other but I've colorized all my comments. > {-# LANGUAGE EmptyDataDecls #-} > module RocketModule(test1, test2, createRocket, addFuel, addO2, launch) where */ object RocketModule { /* None of these data types have constructors, so there are no values with these types. That's okay because I only need the types at compile time. Hence "phantom" - ethereal and unreal. > data NoFuel > data Fueled > data NoO2 > data HasO2 */ sealed trait NoFuel sealed trait Fueled sealed trait NoO2 sealed trait HasO2 /* The Rocket data type takes two type parameters, fuel and o2. But the constructor doesn't touch them. I don't export the constructor so only this module can create rockets. > data Rocket fuel o2 = Rocket */ final case class Rocket[Fuel, O2] private[RocketModule]() /* createRocket produces a rocket with no fuel and no o2 > createRocket :: Rocket NoFuel NoO2 > createRocket = Rocket */ def createRocket = Rocket[NoFuel, NoO2]() /* addFuel takes a rocket with no fuel and returns one with fuel. It doesn't touch the o2 > addFuel :: Rocket NoFuel o2 -> Rocket Fueled o2 > addFuel x = Rocket */ def addFuel[O2](x : Rocket[NoFuel, O2]) = Rocket[Fueled, O2]() /* Similarly, addO2 adds o2 without touching the fuel > addO2 :: Rocket fuel NoO2 -> Rocket fuel HasO2 > addO2 x = Rocket */ def addO2[Fuel](x : Rocket[Fuel, NoO2]) = Rocket[Fuel, HasO2]() /* launch will only launch a rocket with both fuel and o2 > launch :: Rocket Fueled HasO2 -> String > launch x = "blastoff" */ def launch(x : Rocket[Fueled, HasO2]) = "blastoff" /* This is just a pretty way of stringing things together, stolen shamelessly from F#. Adding infix operations is a bit verbose in Scala. > a |> b = b a */ implicit def toPiped[V] (value:V) = new { def |>[R] (f : V => R) = f(value) } /* Create a rocket, fuel it, add o2, then launch it > test1 = createRocket |> addFuel |> addO2 |> launch */ def test1 = createRocket |> addFuel |> addO2 |> launch /* This compiles just fine, too. It doesn't matter which order we put in the fuel and o2 > test2 = createRocket |> addO2 |> addFuel |> launch */ def test2 = createRocket |> addO2 |> addFuel |> launch //This won't compile - there's no fuel // > test3 = createRocket |> addO2 |> launch // def test3 = createRocket |> addO2 |> launch // This won't compile either - there's no o2 // > test4 = createRocket |> addFuel |> launch // def test4 = createRocket |> addFuel |> launch // This won't compile because you can't add fuel twice // > test5 = createRocket |> addFuel |> addO2 |> addFuel |> launch // def test5 = createRocket |> addFuel |> addO2 |> addFuel |> launch }
Monday, October 18, 2010
Phantom Types In Haskell and Scala
Subscribe to:
Post Comments (Atom)
5 comments:
nice your blog and very nice dear your blog psoting we like its you can see our also website for online shopping
batterie ordinateur portable batterie-ordinateur-portable.org - AGO Technologie est speialis dans la vente ordinateur portable, Ordinateur, piles et le Chargeur. Nous offre Batterie Ordinateur Portable, Batterie Ordinateur Portable Sony, Batterie Ordinateur Portable Dell, Chargeur Ordinateur Portable Sony, Chargeur Ordinateur Portable Hp et Chargeur Ordinateur Portable IBM.
I wonder what bytecode will be produced by the Scala compiler. How much of that stuff will be optimized away?
Great post! :)
can this be more complicated
I want to do this but suppose you had lots of other parameters that you want to check at various specific points. Unfortunately you are then carrying around a lot of phantom type parameters. Would it be possible in Haskell to combine them in a single blob somehow?
This seems to answer the question for Scala, but I'm not using that!
https://gist.github.com/2880013
Post a Comment