Created
November 11, 2011 23:51
-
-
Save einblicker/1359705 to your computer and use it in GitHub Desktop.
dynamic scope emulation by reader monad
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 scalaz._ | |
| import Scalaz._ | |
| import util.continuations._ | |
| import collection.mutable.LinkedHashMap | |
| object DynamicScopeEmulation extends App { | |
| //see also: https://gist.github.com/1338773 | |
| object ReifyReflect { | |
| def reify[M[_] : Monad, A](body: => A @cps[M[A]]): M[A] = | |
| reset{val result: A = body; implicitly[Monad[M]].pure[A](result)} | |
| implicit def monad2reflect[M[_] : Monad, A](action: M[A]) = new { | |
| def reflect[B]: A @cps[M[B]] = | |
| shift{(k: A => M[B]) => implicitly[Monad[M]].bind(action, k)} | |
| } | |
| } | |
| object ReaderMonad { | |
| type Env = LinkedHashMap[String, Any] | |
| class Reader[A](f: Env => A) { | |
| def apply(env: Env): A = f(env) | |
| } | |
| implicit def readerMonad: Monad[Reader] = new Monad[Reader] { | |
| def pure[A](x: => A) = new Reader(_ => x) | |
| def bind[A, B](a: Reader[A], f: A => Reader[B]): Reader[B] = { | |
| new Reader[B](env => f(a(env))(env)) | |
| } | |
| } | |
| def ask = new Reader(identity) | |
| def local[A](f: Env => Env, c: Reader[A]) = | |
| new Reader(e => c(f(e))) | |
| } | |
| //reference page: https://sites.google.com/site/scalajp/home/scala-tips/dynamic_variable | |
| object JsonBuilder { | |
| import ReifyReflect._ | |
| import ReaderMonad._ | |
| def json(x: => Env @cps[Reader[Env]]): Env = { | |
| reify(x).apply(LinkedHashMap()) | |
| } | |
| class ArrowOperatorExtension(key: String) { | |
| def ->(value: Any): (String, Any) @cps[Reader[Env]] = { | |
| val result = (key, value) | |
| val status = ask.reflect[Env] | |
| status += result | |
| result | |
| } | |
| } | |
| def %(children: => (String, Any) @cps[Reader[Env]] ): Env @cps[Reader[Env]] = { | |
| local(_ => LinkedHashMap(), reify{ | |
| children | |
| ask.reflect[Env] | |
| }).reflect[Env] | |
| } | |
| def $(elements: Any*): List[Any] = elements.toList | |
| implicit def string2ArrowOperatorExtension(key: String) | |
| : ArrowOperatorExtension = { | |
| new ArrowOperatorExtension(key) | |
| } | |
| } | |
| import JsonBuilder._ | |
| val obj = json{%{ | |
| "X" -> 1 | |
| "Y" -> 2 | |
| "Z" -> 4 | |
| "nums" -> $(1, 2, 3, 4, 5, | |
| %{"hoge" -> 1; "foo" -> 2}) | |
| }} | |
| println(obj) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment