Last active
November 25, 2015 15:51
-
-
Save kenbot/6a5421fe040c485746f2 to your computer and use it in GitHub Desktop.
Garden Hoses as a Category in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Category | |
// | |
trait Category[Arrow[_,_]] { | |
def compose[A,B,C](c1: Arrow[B,C], c2: Arrow[A,B]): Arrow[A,C] | |
def id[A]: Arrow[A,A] | |
} | |
object Category { | |
implicit object FunctionCat extends Category[Function1] { | |
def compose[A,B,C](f: B => C, g: A => B): A => C = f compose g | |
def id[A]: A => A = identity | |
} | |
} | |
// Connection types | |
// In order of water flow | |
trait WaterSupply | |
trait TapScrew | |
trait FemaleMale | |
trait MaleHose | |
trait HoseFemale | |
trait Exit | |
sealed trait Hose[In, Out] { | |
def leaks: Int | |
def kinked: Boolean | |
final def <<[A](in: Hose[A, In]): Hose[A, Out] = | |
in >> this | |
final def >>[A](out: Hose[Out, A]): Hose[In, A] = (this, out) match { | |
case (_, _) => new >>[In, Out, A](this, out) | |
} | |
} | |
// Fills in some fields for hard gadgety hose components | |
trait HoseGadget[In, Out] extends Hose[In, Out] { | |
def leaky: Boolean | |
override final def kinked = false | |
override final def leaks: Int = if (leaky) 1 else 0 | |
} | |
case class Tap(leaky: Boolean) extends HoseGadget[WaterSupply, TapScrew] | |
case class TapNozzle(leaky: Boolean) extends HoseGadget[TapScrew, FemaleMale] | |
case class MaleNozzle(leaky: Boolean) extends HoseGadget[FemaleMale, MaleHose] | |
case class HosePipe(leaks: Int, kinked: Boolean) extends Hose[MaleHose, HoseFemale] | |
case class FemaleNozzle(leaky: Boolean) extends HoseGadget[HoseFemale, FemaleMale] | |
case class SprayGun(leaky: Boolean) extends HoseGadget[FemaleMale, Exit] | |
case class Sprinkler(leaky: Boolean) extends HoseGadget[FemaleMale, Exit] | |
// Identity hose | |
case class EmptyHose[A] extends Hose[A, A] { | |
def leaks = 0 | |
def kinked = false | |
} | |
// Composition of two hoses | |
case class >>[In, Mid, Out]( | |
in: Hose[In, Mid], | |
out: Hose[Mid, Out]) extends Hose[In, Out] { | |
def kinked = in.kinked || out.kinked | |
def leaks = in.leaks + out.leaks | |
override def toString: String = s"$in >> $out" | |
} | |
object Hose { | |
implicit object HoseCategory extends Category[Hose] { | |
def compose[A,B,C](c1: Hose[B,C], c2: Hose[A,B]): Hose[A,C] = | |
c1 << c2 | |
def id[A]: Hose[A,A] = EmptyHose[A] | |
} | |
def empty[A]: Hose[A,A] = EmptyHose[A] | |
def newHose: Hose[FemaleMale, FemaleMale] = | |
MaleNozzle(false) >> HosePipe(0, false) >> FemaleNozzle(false) | |
def oldHose(leaks: Int, kinked: Boolean) = | |
MaleNozzle(false) >> HosePipe(leaks, kinked) >> FemaleNozzle(false) | |
def newSprayGun = SprayGun(false) | |
def newSprinkler = Sprinkler(false) | |
def newFittedTap = Tap(false) >> TapNozzle(false) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment