Created
April 3, 2014 18:15
-
-
Save melrief/9959753 to your computer and use it in GitHub Desktop.
Scala + Scalaz implementation of http://www.haskellforall.com/2013/05/program-imperatively-using-haskell.html?spref=tw
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
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 | |
} |
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
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