Comming from Common Lisp, I'm trying to use let to shadow the value of a global variable dynamically.
(setv glob 18)
(defn callee []
(print glob))
(defn nonl [x]
(callee)
(let [glob x]
(callee))
(callee))
(nonl 39)
=>
18
18
18
Is there a way to make this work so that the second call to callee gives 39?
[EDIT]
Based on gilch's response i wrote the following draft using contextvars:
(import contextvars :as cv)
(defmacro defparam [symbol value]
(let [command (. f"{symbol} = cv.ContextVar('{symbol}')")]
`(do (exec ~command)
(.set ~symbol ~value))))
(defmacro parameterize [symbol value #* body]
`(. (cv.copy-context)
(run (fn [] (do (.set ~symbol ~value)
~@body)))))
(defn callee []
(glob.get))
;;;;;;;;;
(defparam glob 18)
(callee) => 18
(parameterize glob 39
(callee)) => 39
(callee) => 18
Thanks for the answers!
There's no built-in way to give a global variable a dynamically scoped temporary value in Python (and Hy doesn't add a macro for it or anything), so you have to do it yourself:
(setv glob 18)
(defn callee []
(print glob))
(defn nonl [x]
(callee)
(global glob)
(setv old-glob glob)
(try
(setv glob x)
(callee)
(finally
(setv glob old-glob)))
(callee))
(nonl 39)
A macro for this might look like:
(defmacro dyn-rebind-global [symbol new-value #* body]
(setv old-value (hy.gensym))
`(do
(global ~symbol)
(setv ~old-value ~symbol)
(try
(setv ~symbol ~new-value)
~@body
(finally
(setv ~symbol ~old-value)))))
Then you could use it like this:
(setv glob 18)
(defn callee []
(print glob))
(defn nonl [x]
(callee)
(dyn-rebind-global glob x
(callee))
(callee))
(nonl 39)