Skip to content

Instantly share code, notes, and snippets.

@hhanh00
Last active August 29, 2015 14:23
Show Gist options
  • Save hhanh00/a63565094a69643aa532 to your computer and use it in GitHub Desktop.
Save hhanh00/a63565094a69643aa532 to your computer and use it in GitHub Desktop.
Multi level lens with scalaz
import scalaz._
case class Valuation(realized: BigDecimal, unrealized: BigDecimal) {
def addR(r: BigDecimal) = this copy (realized = this.realized+r)
def addU(u: BigDecimal) = this copy (unrealized = this.unrealized+u)
}
object Valuation {
def apply() = new Valuation(0, 0)
}
case class Holding(symbol: String, quantity: Int, valuation: Valuation)
object Holding {
def default(symbol: String) = new Holding(symbol, 1, Valuation()) // give 1 share for free!
}
case class Portfolio(user: String, holdings: Map[String, Holding], valuation: Valuation)
case class Global(portfolios: Map[String, Portfolio], valuation: Valuation)
object Hello extends App {
val g = Global(Map.empty, Valuation())
def globalL(user: String) = Lens.lensu[Global, Portfolio]((g, p) => g copy (portfolios = g.portfolios.updated(user, p)), _.portfolios.getOrElse(user, Portfolio(user, Map.empty, Valuation())))
val globalValuationL = Lens.lensu[Global, Valuation]((p, v) => p copy (valuation = v), _.valuation)
def portfolioL(symbol: String) = Lens.lensu[Portfolio, Holding]((p, h) => p copy (holdings = p.holdings.updated(symbol, h)), _.holdings.getOrElse(symbol, Holding.default(symbol)))
val portfolioValuationL = Lens.lensu[Portfolio, Valuation]((p, v) => p copy (valuation = v), _.valuation)
val holdingL = Lens.lensu[Holding, Valuation]((h, v) => h copy (valuation = v), _.valuation)
def applyValuationMod(user: String, symbol: String)(f: Valuation => Valuation) = {
val h = globalL(user) >=> portfolioL(symbol) >=> holdingL
val p = globalL(user) >=> portfolioValuationL
val g = globalValuationL
List(h, p, g) map(_ =>= f) reduceLeft (_ andThen _)
}
def applyMark(symbol: String)(markFunc: Holding => Valuation) = { (global: Global) =>
global.portfolios.foldLeft(global) { case (g, (user, pf)) =>
val f = pf.holdings.get(symbol) map (h => (valuation: Valuation) => valuation.addU(markFunc(h).unrealized - h.valuation.unrealized))
(f map (fv => applyValuationMod(user, symbol)(fv)) getOrElse identity[Global] _)(g)
}
}
def applyValuationModOnSymbol(symbol: String)(f: Valuation => Valuation) = { (global: Global) =>
global.portfolios.keys.foldLeft(global)((g, user) => applyValuationMod(user, symbol)(f)(g))
}
val f = applyValuationMod("h", "IBM")(_ addR 10.5) andThen applyValuationMod("h", "MSFT")(_ addR 11.5) andThen applyValuationMod("c", "AAPL")(_ addU -10.0)
val g2 = f(g)
println(g2)
val mark = (h: Holding) => Valuation(0, h.quantity*100)
println(applyMark("IBM")(mark)(g2))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment