Created
March 11, 2015 20:22
-
-
Save lazyvalue/8831270f8b3377e59f49 to your computer and use it in GitHub Desktop.
Module examples worksheet
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
// Case classes | |
// Algebraic Data Types | |
// Objects | |
// Currying | |
// Traits | |
// Classes | |
// The Cake | |
// CASE CLASSES | |
case class CreepyBug(name: String, numberOfEyes: Int, canBeKilledByFire: Boolean) | |
// This code is generated for you! | |
// An actual class. | |
// The compiler will sometimes try to unify types to Product if you make a mistake. | |
class CreepyBug(val name: String, val numberOfEyes: Int, val canBeKilledByFire: Boolean) | |
extends Product { | |
def toString | |
def equals | |
def hashCode | |
def copy(name = this.name, numberOfEyes = this.numberOfEyes, | |
canBeKilledByFire = this.canBeKilledByFire) = | |
new CreepyBug(name, numberOfEyes, canBeKilledByFire) | |
} | |
val x = new CreepyBug("creepy") | |
val z = CreepyBug.apply("creepy") | |
val y = CreepyBug("creepy") | |
// A companion object! | |
object CreepyBug { | |
def apply(val name: String, val numberOfEyes: Int, val canBeKilledByFire: Boolean) = new CreepyBug(name, numberOfEyes, canBeKilledByFire) | |
} | |
object FriendlyBug { | |
def apply(numberOfEyes: Int) = CreepyBug("friendly", numberOfEyes, true) | |
} | |
val w: CreepyBug = FriendlyBug(42) | |
// ALGEBRAIC DATA TYPES | |
sealed trait Creature { | |
val lifeForce = // we will get to this | |
} | |
case class CreepyBug(numberOfLegs: Int, numberOfEyes: Int, | |
canBeKilledByFire: Boolean) extends Creature | |
case class Lizard(hasScales: Boolean, spits: Boolean) extends Creature | |
case class Monkey(idol: Idol, sneaky: Boolean, esteem: Int) extends Creature | |
sealed trait Idol | |
case object SunIdol extends Idol | |
case object MoonIdol extends Idol | |
case object UnderworldIdol extends Idol | |
// Algebra = (MAX_INT * MAX_INT * 2 [Boolean]) for CreepyBug + (2 * 2) for Lizard + (2 * numIdols * MAX_INT (esteem)) for Monkey | |
// Our match is total | |
def findHome(creature: Creature): InputOutput[Home] = creature match { | |
case CreepyBug(_, eyes, z, a) => | |
if(eyes > 42) println("How many eyes you have!") | |
Ground | |
case lizard: Lizard => Swamp | |
case monkey: Monkey => Tree | |
//case _ => throw new Exception | |
} | |
// CURRYING! | |
object MonkeyTools { | |
def offering(monkey: Monkey, idol: Idol)(item: Sacrifice): Monkey = { | |
println("Thanks for the sacrifice! " + item) | |
monkey.copy(idol = idol) | |
} | |
// Ofering can be partially applied. Now this Function can be passed around as a constructor | |
val fruitBaked: Sacrifice = new Sacrifice | |
val itemFunction: Sacrifice => Monkey = offering(evilMonkey, MoonIdol) | |
val result: Monkey = itemFunction(fruitBasket) | |
// On a side note: you can curry as much as you want | |
val multiplyThreeNumbers: Int => Int => Int => Int = (w: Int) => (x: Int) => (y: Int) =>( z:Int) => w * x * y * z | |
} | |
// Another constructor example | |
// Really hard to get ahold of these LifeForces | |
case class LifeForce(good: Int, lawful: Int, powerRating: Int, source: Idol, tetherToTheCosmos: CosmosTether) | |
// Another definition of lizard | |
abstract class Lizard(hasScales: Boolean, spits: Boolean) extends Creature { | |
val lifeForce: LifeForce | |
} | |
object Lizard { | |
def apply(inLifeForce: LifeForce)(hasScales: Boolean, spits: Boolean) = new Lizard(hasScales, spits) { | |
val lifeForce = inLifeForce | |
} | |
} | |
// Dependency inject Lifeforce at the top | |
// LifeForce at the top, and then just pass around the rest of the constructor | |
val myLifeForce = // thousands of years of making a life force | |
val lizardBuilder: (Boolean, Boolean) => Lizard = Lizard(myLifeForce) | |
// Our offering example felt incomplete. Let's make it better. | |
trait AcceptsOffering[T, I] { | |
def offer(x: T): Blessing | |
} | |
object Idols { | |
implicit val sunIdolFruit = new AcceptsOffering[FruitBasket, SunIdol] { | |
def offer(x: FruitBasket) = { | |
println("THANK YOU!") | |
SunIdol.blessing | |
} | |
} | |
implicit val underworldBugs = new AcceptsOffering[CreepyBug, UnderworldIdol] { | |
def offer(x: CreepyBug) = { | |
println("The Underworld is pleased.") | |
UnderworldIdol.blessing | |
} | |
} | |
} | |
object OfferingTools { | |
import Idols._ | |
def offering[T,I](monkey: Monkey, item: T, idol: I)(implicit ao: AcceptsOffering[T, I]): Monkey = { | |
ao.offer(item) | |
monkey.copy(idol = idol) | |
} | |
val someMonkey: Monkey = Monkey(...) | |
val someBug: CreepyBug = CreepyBug(...) | |
// Works! | |
offering(someMonkey, someFruitBasket, SunIdol) | |
// Works! | |
offering(someMonkey, someBug, UnderworldIdol) | |
// Does not compile! | |
offering(someMonkey, someBug, SunIdol) | |
// Does not compile, the Moon Idol is silent! | |
offering(someMonkey, shinyRock, MoonIdol) | |
} | |
// TRAITS | |
trait Jungle { | |
val creatures: Set[Creature] | |
} | |
val myJungle = new Jungle { | |
val creatures = Set(someBug) | |
} | |
object Jungle { | |
def apply(inCreatures: List[Creatures]) = new Jungle { | |
val creatures = Set(inCreatures) | |
} | |
} | |
// Traits offer multiple inheritence. | |
// An object can have multiple traits. | |
// Traits can be abstract or partially abstract | |
// Traits COPY all of their values into whoever they are inheriting. | |
// Use traits sparingly | |
// Classes are classes | |
// A cake is a way of layering in dependencies | |
trait LifeForceProvider { | |
val lifeForce: LifeForce | |
} | |
trait BugFactoryModule { | |
val bugFactory: BugFactory | |
class BugFactory { | |
def makeABug(lifeForce: LifeForce): CreepyBug | |
} | |
} | |
trait TreeFactoryModule { | |
val treeFactory: TreeFactory | |
class TreeFactory { | |
def makeATree(lifeForce: LifeForce): Tree | |
} | |
} | |
trait MonkeyFactoryModule extends TreeFactoryModule with LifeForceProvider { | |
val monkeyFactory: MonkeyFactory | |
class MonkeyFactory { | |
def makeAMonkey: Monkey | |
def makeMonkeyWithTree: (Monkey,Tree) = (makeAMonkey, treeFactory.makeATree(lifeForce)) | |
} | |
} | |
// THIS IS STILL ABSTRACT!!! | |
trait Jungle extends LifeForceProvider with BugFactoryModule with TreeFactoryModule with MonkeyFactoryModule{ | |
val myTrees = Range(0, 500).map(_ => makeATree(lifeForce)) | |
val myBugs = Range(0,200).map(_ => makeABug(lifeForce)) | |
val monkeys = Range(0,500).map(_ => makeMonkeyWithTree) | |
} | |
val aRealJungle = new Jungle with EvilLifeForceProvider with SuperCreepyBugs with DroopyTrees with MoonMonkeys |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment