Created
March 12, 2015 19:52
-
-
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)
This file contains hidden or 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
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