Skip to content

Instantly share code, notes, and snippets.

@melrief
Created April 3, 2014 18:15
Show Gist options
  • Save melrief/9959753 to your computer and use it in GitHub Desktop.
Save melrief/9959753 to your computer and use it in GitHub Desktop.
import scala.language.higherKinds
import scala.math.{pow}
import scalaz._
import Scalaz._
import scalaz.effect._
case class Point(_x : Double, _y : Double)
case class GameUnit(_health : Int, _position : Point)
case class Game(_score : Int, _units : List[GameUnit], _boss : GameUnit)
object Lenses { // a.k.a. boilerplate
val score : Lens[Game,Int] = Lens.lensu(
(game,newScore) => game.copy(_score = newScore), _._score )
val units : Lens[Game,List[GameUnit]] = Lens.lensu (
(game,newUnits) => game.copy(_units = newUnits), _._units )
val boss : Lens[Game,GameUnit] = Lens.lensu (
(game,newBoss) => game.copy(_boss = newBoss), _._boss )
val health : Lens[GameUnit,Int] = Lens.lensu (
(game,newHealth) => game.copy(_health = newHealth), _._health )
val position : Lens[GameUnit,Point] = Lens.lensu (
(game,newPosition) => game.copy(_position = newPosition), _._position )
val x : Lens[Point,Double] = Lens.lensu (
(point,newX) => point.copy(_x = newX), _._x )
val y : Lens[Point,Double] = Lens.lensu (
(point,newY) => point.copy(_y = newY), _._y )
}
object Main {
import Lenses._
// types
type GameState[M[+_],A] = StateT[M,Game,A]
type GameStateIO[A] = GameState[IO,A]
// utils for the IO monad
def putStrLn(s : String) : IO[Unit] = println(s).pure[IO]
def putAnyLn(a : Any) : IO[Unit] = putStrLn(a.toString)
// utils for the GameStateIO monad
def io[A](f : IO[A]) : GameStateIO[A] = MonadTrans[GameState].liftM(f)
def mod(f : Game => Game) : GameStateIO[Unit] = modify(f).lift
// game functions
def strike : GameStateIO[Int] = {
io( putStrLn("*shink*") ) >>
(boss >=> health -= 10).lift
}
def isInArea(center : Point, radius : Double, unit : GameUnit) : Boolean = {
pow((position >=> x).get(unit) - x.get(center),2) +
pow((position >=> y).get(unit) - y.get(center),2) < pow(radius,2)
}
def fireBreath(target : Point) : GameStateIO[Unit] = {
def fireBreathUnit(u : GameUnit) : GameUnit = {
if (isInArea(target, 1.0, u)) (health.mod(_ - 3,u)) else u
}
io( putStrLn("*rawr*") ) >>
mod(units =>= { _ map fireBreathUnit } )
}
def retreat : GameStateIO[Unit] = {
def changePosition : GameUnit => GameUnit = {
position =>= ((y += 10.0) >> (x += 10.0)).exec
}
io( putStrLn("Retreat!") ) >>
mod(units =>= { _ map changePosition})
}
def battle : GameStateIO[Unit] = for {
// Charge!
_ <- List("Take that!", "and that!", "and that!").traverse { taunt =>
io( putStrLn(taunt) ) >>
strike
}
// The dragon awakes!
_ <- fireBreath(Point(0.5,1.5))
_ <- List(1,2,3).traverse { _ =>
// The better part of valor
retreat >>
// Boss chases them
mod(boss >=> position =>= ((y += 10.0) >> (x += 10.0)).exec)
}
} yield( () )
// state
val initialState : Game = Game(
0
, List( GameUnit(10,Point(3.5,7.0))
, GameUnit(15,Point(1.0,1.0))
, GameUnit(8, Point(0.0,2.1))
)
, GameUnit(100,Point(0.0,0.0))
)
// examples
def printFinalState[A](f : GameStateIO[A]) : IO[Unit] = f.exec(initialState) >>= putAnyLn
def example1 = strike
def example2 = fireBreath(Point(0.5,1.5))
def example3 = strike >>
fireBreath(Point(0.5,1.5)) >>
retreat
// main
def mainIO : IO[Unit] = {
putStrLn("First example:\n") >> printFinalState(example1) >>
putStrLn("\nSecond example:\n") >> printFinalState(example2) >>
putStrLn("\nThird example:\n") >> printFinalState(example3) >>
putStrLn("\nBattle:\n") >> printFinalState(battle)
}
def main(args : Array[String]) : Unit = mainIO.unsafePerformIO
}
name := "Scalaz lenses demonstration"
scalaVersion := "2.10.1"
scalacOptions ++= Seq(
"-feature"
)
libraryDependencies ++= Seq(
"org.scalaz" % "scalaz-core_2.10" % "7.0.6"
,"org.scalaz" % "scalaz-effect_2.10" % "7.0.6"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment