Fork me on GitHub
#clojure
<
2023-04-09
>
Jakub Šťastný02:04:12

Are people using the contextual-eval from The joy of Clojure? It's pretty cool, but I found it broken for things that cannot serialise into a valid CLJ, Java objects, exceptions, that sort of things. For instance it may try to eval this:

(clojure.core/let [e (quote #error {
 :cause "error"
 :data {:thrown true}
 :via
 [{:type clojure.lang.ExceptionInfo...] e)
Are there any work-arounds? Can it be fixed somehow? It's such a useful thing but only works for CLJ values and blows up when anything non-CLJ (even including exceptions) get into the lexical scope. Ref: https://gist.github.com/leobm/6061734.

phronmophobic03:04:01

Instead of embedding the values, I would use eval to create a function and call it:

(defn contextual-eval [ctx expr]
  (let [f
        (eval                                           
         `(fn [~@(keys ctx)]
            ~expr))]
    (apply f (vals ctx))))

> (contextual-eval {'a (Exception. "hi")
                  'b 2}
                 '(str (.getMessage a) " " b))
;; "hi 2"

phronmophobic04:04:41

You can also do something like save the values in a dynamic variable and then grab the values inside of the eval from the dynamic variable, but I think wrapping in a function is more explicit and less brittle.

Jakub Šťastný10:04:47

Thanks @U7RJTCH6J, just what I needed!

p-himik09:04:16

I have a deeply nested set of forms like reduce->let->reduce->let->reduce->let->reduce that needs to propagate the innermost reduced to the top. When I don't have let, it seems that the combination transduce + reduced over a composition of mapcat transducers is a reasonable solution. But it doesn't work that well with lets. I'm pretty sure there was a macro for it somewhere but struggling to find it. Any ideas? Maybe a better approach altogether?

p-himik09:04:28

for with interspersed :let and :when fits perfectly in terms of structure. But it's not suitable because (first (for ...)) will do a lot more work than needed.

p-himik09:04:06

Only if it were better-for. :D Or rather, eager-for-supporting-reduced.

p-himik10:04:59

loopr from dom-top is very nice but doesn't support :let. :(

Ben Sless10:04:29

Doesn't xforms have a for macro which returns a transducer?

💡 3
p-himik10:04:31

Ah, neat, thanks!

Ben Sless10:04:24

Good to know my encyclopedic knowledge of the ecosystem isn't wasted (yet) (we should get a LLM to do that)

kennytilton12:04:51

@U3E46Q1DG? The Dart guy? Oh, wait, he started on Common Lisp. Good 🧬 tells!

😀 1
raspasov23:04:03

Love the xforms library.

🙏 1
raspasov23:04:19

@U2FRKM4TW you have a gist to share? Hard to picture the problem in my head.

p-himik07:04:02

Sure, here's something I came up with on the spot. Although it's in Python, specifically to demonstrate that there it's a no-brainer, and that I had to rewrite some similar code in Clojure. :)

def find_red_item(items):
    for item in items:
        net = build_network(item)
        nodes = find_affected_nodes(net)
        for n in nodes:
            max_depth = get_max_depth(n, net)
            for d in range(max_depth):
                es = get_relevant_edges(net, n, d)
                for e in es:
                    if get_attr(e, 'color') == 'red':
                        return item, n, e