This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (3)
- # babashka (64)
- # bangalore-clj (1)
- # beginners (12)
- # calva (21)
- # cider (7)
- # clj-kondo (16)
- # cljdoc (1)
- # clojure (49)
- # clojure-dev (2)
- # clojure-europe (10)
- # clojure-germany (3)
- # clojure-italy (1)
- # clojure-uk (13)
- # clojuredesign-podcast (6)
- # clojurescript (2)
- # code-reviews (21)
- # data-science (2)
- # datomic (3)
- # emacs (20)
- # events (1)
- # fulcro (2)
- # graphql (4)
- # java (3)
- # malli (14)
- # off-topic (45)
- # re-frame (2)
- # shadow-cljs (7)
- # tools-deps (167)
- # vrac (14)
- # xtdb (4)
Ah, fixed this by writing interleave like this
I think the error above came from a fundamental misunderstanding of macros, and was worsened by the fact that interleave already exists:
(defn interleave* [s1 delayed-s2] (cons-stream (car-stream s1) (interleave* (my-force delayed-s2) (my-delay (cdr-stream s1))))) (defmacro interleave [s1 s2] `(interleave* ~s1 (my-delay ~s2)))
I defined this as a recursive function, but i realize this can’t work for macros — it would need to expand all the time. I guess it evaled because
(defmacro interleave [s1 s2] `(cons-stream (car-stream ~s1) (interleave ~s2 (cdr-stream ~s1))))
interleaveinside the macro referred to
@U0C5DE6RK you can have recursive macros, but they have to operate on the form passed in, not the value:
This breaks down the sequence passed in directly and either returns a form that recursively expands only the tail of the sequence, or a non-recursive expression
user=> (defmacro trial [x] (if (seq x) `(do (println ~(first x)) (trial ~(rest x))) :done)) #'user/trial user=> (trial [1 2 3]) 1 2 3 :done user=>
user=> (macroexpand '(trial [1 2 3])) (do (clojure.core/println 1) (user/trial (2 3))) user=> (macroexpand '(trial (2 3))) (do (clojure.core/println 2) (user/trial (3))) user=> (macroexpand '(trial (3))) (do (clojure.core/println 3) (user/trial ())) user=> (macroexpand '(trial ())) :done user=>
Hey Sean, tried playing with this a bit:
trial, it seems like
interleave should work as a recursive macro too (as it only works on the forms)
macroexpand seems to do what I expect:
(defmacro rec-interleave [s1 s2] `(cons-stream (car-stream ~s1) (rec-interleave ~s2 (cdr-stream ~s1))))
Buut, if I try to evaluate
(macroexpand '(rec-interleave integers integers)) => [(chp3/car-stream integers) (chp3/my-delay (chp3/rec-interleave integers (chp3/cdr-stream integers)))]
(def x (rec-interleave integers integers))
--- Am not quite sure how to debug further from that error. Do you have thoughts on what could be happening?
Execution error (NoClassDefFoundError) at nrepl.middleware.interruptible-eval/evaluate (interruptible_eval.clj:79). Could not initialize class clojure.lang.Compiler$CompilerException
@U0C5DE6RK My first suspicion would be that it is an infinite evaluation. But I always advise debugging things in a plain REPL, without nREPL and all that other stuff that tries to "help" manage evaluation and display of results.
Without seeing a self-contained, repeatable project up on GitHub containing this code, it would be hard for me to suggest anything further.
Thanks Sean! https://github.com/stopachka/interleave-demo-for-sean ---
Okay I think I understand why my thing is not working. Indeed it is trying to eval in a loop
I am not sure how my interleave is different from the
Perhaps the big thing is the
if — if doesn’t eval the the forms until runtime, while mine evals at compile time.
Just looked at this -- now I can see what the other functions/macros are -- and you're falling into the same trap I talked about above: your macroexpansion has no "bottom" at compile time so it just recursively expands until you get a stackoverflow.
The example I gave works because it is analyzing forms at compile time and so it can tell when it hits the end of a form. It wouldn't work with bound names because those are not sequence forms.
(rec-interleave integers integers) expands to
[(interleave.demo/car-stream integers) (interleave.demo/my-delay (interleave.demo/rec-interleave integers (interleave.demo/cdr-stream integers)))] but in trying to evaluate that the remaining
rec-interleave call is macroexpanded again and it always produces a larger form. Hence the infinite loop during evaluation.
Am close but don’t quite get the difference between trial and interleave:
> It wouldn’t work with bound names because those are not sequence forms.
Do you mind expounding a bit? What is the difference between a
bound name and a
How does the compiler know that it shouldn’t do anything when it sees
(defmacro trial [x] (if (seq x) `(do (println ~(first x)) (trial ~(rest x))) :done))
It does do something -- it expands it. But pay attention to what actually happens as you expand it each time:
user=> (macroexpand '(trial [1 2 3])) (do (clojure.core/println 1) (user/trial (2 3))) user=> (macroexpand '(trial [2 3])) (do (clojure.core/println 2) (user/trial (3))) user=> (macroexpand '(trial )) (do (clojure.core/println 3) (user/trial ())) user=> (macroexpand '(trial )) :done user=>
It's processing the form
[1 2 3] at compile-time, not the runtime value
[1 2 3].
user=> (def x [1 2 3]) #'user/x user=> (macroexpand '(trial x)) Syntax error macroexpanding trial at (REPL:12:1). Don't know how to create ISeq from: clojure.lang.Symbol user=>
xis not a sequence so the compile-time call to
xis not evaluated here because we're in the Read phase still, we haven't reached evaluation, so there are no runtime values.