Last active
November 27, 2020 22:29
-
-
Save lilactown/ca6686f20a0d55a3e3558f144ace6a68 to your computer and use it in GitHub Desktop.
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
(ns eff.global-scope | |
(:import | |
(java.lang Continuation ContinuationScope))) | |
(let [effect-scope (ContinuationScope. "effect") | |
state (atom 0) | |
;; track what effect is currently being performed, | |
;; and what we're going to return | |
effect-performing (atom nil) | |
effect-returning (atom nil) | |
;; this atom gets set any time we `perform` | |
;; if we do not `resume`, this is left as `false` | |
stopped? (atom false) | |
resume (fn resume | |
([] | |
(resume nil)) | |
([x] | |
(reset! effect-returning x) | |
(reset! stopped? false) | |
nil)) | |
put-state (fn [x] | |
(reset! state x) | |
(resume x)) | |
get-state (fn [] | |
(resume @state)) | |
stop (fn [] | |
(prn "stopping")) | |
perform (fn [& args] | |
;; any time we perform an effect, we yield to the parent context | |
;; and set some state that declares what effect is currently | |
;; performed | |
(reset! effect-performing (vec args)) ; e.g. [:get], [:put 2] | |
(Continuation/yield effect-scope) | |
;; once we've resumed (if we do), capture the return value | |
;; passed into `resume` and clear the global state | |
(let [ret @effect-returning] | |
(reset! effect-performing nil) | |
(reset! effect-returning nil) | |
ret)) | |
;; create a continuation wrapping our effect-ful function | |
c1 (Continuation. | |
effect-scope | |
(fn [] | |
(println "-") | |
(prn :get (perform :get)) | |
(println "--") | |
(perform :put 1) | |
#_(perform :stop) | |
(prn :get (perform :get)) | |
(println "---") | |
(perform :put 2) | |
#_(perform :stop) | |
(prn :get (perform :get))))] | |
(while (and (not @stopped?) (not (.isDone c1))) | |
(.run c1) | |
(reset! stopped? true) | |
;; handle effects | |
;; e.g. [:get], [:put 2] | |
(case (first @effect-performing) | |
:get (get-state) | |
:put (put-state (second @effect-performing)) | |
:stop (stop) | |
nil nil)) | |
(prn @state @effect-performing @effect-returning @stopped?)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment