Skip to content

Instantly share code, notes, and snippets.

@EECOLOR
Created March 12, 2015 19:52
Show Gist options
  • Save EECOLOR/632ce76597efe2a2d4e6 to your computer and use it in GitHub Desktop.
Save EECOLOR/632ce76597efe2a2d4e6 to your computer and use it in GitHub Desktop.
If characters were chocolate and parsers were girls, what would happen? (this code has not been tested, that would have been a mess)
object Party {
type Chocolate = Char
type Sticker = Any
def complain(c: Chocolate) = abort(s"You should have asked me if I wanted `$c`")
sealed trait Girl {
def willYouEat(c: Chocolate): VagueAnswer
def eat(c: Chocolate): (Rating, Girl)
}
sealed trait VagueAnswer
case object Yuk extends VagueAnswer
sealed trait Rating extends VagueAnswer
case object MorePlease extends Rating
case object ImStuffed extends Rating
case class LyingGirl(client: Girl) extends Girl {
def willYouEat(c: Chocolate) =
client.willYouEat(c) match {
case MorePlease => ImStuffed
case _ => MorePlease
}
def eat(c: Chocolate) = MorePlease -> this
}
case class CoverGirl(client: Girl) extends Girl {
def willYouEat(c: Chocolate) =
client.willYouEat(c) match {
case MorePlease => MorePlease
case _ => ImStuffed
}
def eat(c: Chocolate) = {
val (rating, girl) = client.eat(c)
val newRating =
rating match {
case MorePlease => MorePlease
case _ => complain(c)
}
newRating -> girl
}
}
case class HippyTechGirl(client: Girl, served: Indexed[Girl] = emptyValue)(clone: Girl = client) extends Girl {
def willYouEat(c: Chocolate) =
clone.willYouEat(c) match {
case Yuk => ImStuffed
case _ => MorePlease
}
def eat(c: Chocolate) = {
val (rating, girl) = clone.eat(c)
rating match {
case ImStuffed => MorePlease -> HippyTechGirl(client, served :+ girl)()
case MorePlease => MorePlease -> HippyTechGirl(client, served)(clone = girl)
case _ => complain(c)
}
}
}
case class DemandingGirl(client: Girl, served: Indexed[Girl] = emptyValue)(clone: Girl = client) {
def willYouEat(c: Chocolate) =
clone.willYouEat(c) match {
case Yuk if served.nonEmpty => ImStuffed
case Yuk => Yuk
case ImStuffed => client.willYouEat(c)
case MorePlease => MorePlease
}
def eat(c: Chocolate) = {
val eater =
clone.willYouEat(c) match {
case ImStuffed => client
case MorePlease => clone
case Yuk => complain(c)
}
val (rating, girl) = eater.eat(c)
rating match {
case ImStuffed => MorePlease -> new DemandingGirl(client, served :+ girl)()
case MorePlease => MorePlease -> new DemandingGirl(client, served)(clone = girl)
}
}
}
case class SecretaryGirl(client: Girl, fed: Indexed[Chocolate] = emptyValue) extends Girl {
def willYouEat(c: Chocolate) = client.willYouEat(c)
def eat(c: Chocolate) = {
val (rating, girl) = client.eat(c)
rating -> SecretaryGirl(girl, fed :+ c)
}
}
case class StickerGirl(client: Girl, sticker: Sticker) extends Girl {
def willYouEat(c: Chocolate) = client.willYouEat(c)
def eat(c: Chocolate) = {
val (rating, girl) = client.eat(c)
rating -> StickerGirl(girl, sticker)
}
}
case class ConcernedGiveOutGirl[A](line: Linear[Girl]) extends Girl {
private lazy val firstInLine = line.head
private lazy val whatDoIWant = if (line.nonEmpty) MorePlease else ImStuffed
def willYouEat(c: Chocolate) = whatDoIWant match {
case MorePlease => firstInLine.willYouEat(c)
case noMore => noMore
}
def eat(c: Chocolate): (Rating, Girl) = {
lazy val queue = line.tail
val (rating, girl) = firstInLine.eat(c)
rating match {
case MorePlease => MorePlease -> ConcernedGiveOutGirl(girl :: queue)
case ImStuffed if queue.nonEmpty => MorePlease -> ConcernedGiveOutGirl(queue)
case ImStuffed => ImStuffed -> this
}
}
}
case class PleasingGiveOutGirl[A](line: Linear[Girl]) extends Girl {
private lazy val firstInLine = line.head
def willYouEat(c: Chocolate) = {
firstInLine.willYouEat(c) match {
//line.tail.exists(g => (g willYouEat c) === MorePlease)
case Yuk if anyOthersFor(c).nonEmpty => MorePlease
case Yuk if anyOneSatisfied(c).nonEmpty => ImStuffed
case Yuk => Yuk
case MorePlease => MorePlease
case ImStuffed => ImStuffed
}
}
def eat(c: Chocolate): (Rating, Girl) = {
lazy val others = anyOthersFor(c)
val (nextToEat, queue) =
firstInLine.willYouEat(c) match {
case MorePlease => (firstInLine, line.tail)
case Yuk if others.nonEmpty => (others.head, others.tail.toLinear)
case _ => complain(c)
}
val (rating, girl) = nextToEat.eat(c)
rating match {
case ImStuffed => ImStuffed -> this
case MorePlease => MorePlease -> PleasingGiveOutGirl(girl :: queue)
}
}
private def anyOthersFor(c: Chocolate) =
line.tail.filter(_.willYouEat(c) == MorePlease)
private def anyOneSatisfied(c: Chocolate) =
line.tail.filter(_.willYouEat(c) == ImStuffed)
}
case class SelectiveGirl(willEat: Chocolate => VagueAnswer) extends Girl {
def willYouEat(c: Chocolate) = willYouEat(c)
def eat(c: Chocolate): (Rating, Girl) = MorePlease -> this
}
case class WellPreparedGirl(chocolats: Linear[Chocolate]) extends Girl {
def willYouEat(c: Chocolate) =
if (chocolats.isEmpty) ImStuffed
else if (chocolats.head === c) MorePlease
else Yuk
def eat(c: Chocolate): (Rating, Girl) = {
val onTheList = chocolats.tail
if (onTheList.isEmpty) ImStuffed -> this
else MorePlease -> WellPreparedGirl(onTheList)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment