Fork me on GitHub
#clojure-dev
<
2018-09-03
>
tristefigure17:09:53

Hi. I'm trying to define a macro from within a top-level let inside a defn. Then I hope to be able to use the macro within the let's body. However I'm getting the following strange behavior:

tristefigure17:09:25

So it looks like eval understand the-macro indeed is a macro but it seems it "forgets" to pass the invisible &form and &env parameters when it macroexpands it.

tristefigure17:09:19

Now this might look strange, but I'm actually doing something artsy à-là let-over-lambda, experimenting with pertinently non-hygienic macros. This strange configuration is my starting point.

gfredericks17:09:06

I don't think it's working as well as you think

gfredericks17:09:26

my guess is it's not really "macroexpanding", it's pretending your macro is a function

gfredericks17:09:43

try replacing line 14 with (the-macro-2 (not valid code)) to tell the difference

gfredericks17:09:58

I guess you'd have to add more args on line 11 as well

gfredericks17:09:10

(defmacro the-macro-2 [& unused])

tristefigure17:09:17

yes it's not considering "the-macro" as a macro

gfredericks17:09:42

I don't think defmacro is meant to be usable this way

gfredericks17:09:56

line 14 gets compiled before the defmacro even "runs"

tristefigure17:09:25

I would need reader-macros (Common Lisp provides thoses)

tristefigure17:09:29

Sorry, I was actually referring to compiler-macros : https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node101.html

gfredericks17:09:27

clojure doesn't have a separate notion of interpretation

gfredericks17:09:29

it's all compiled

bronsa18:09:59

@tristefigure you can't let a macro like that

bronsa18:09:19

clojure doesn't have letmacro and def* forms are global not lexical

bronsa18:09:43

your the-macro-3 Var is not a macro yet by the time your invocation of it is analysed and compiled

bronsa18:09:01

lexical/local macros is just not something that you can do in clojure

bronsa18:09:38

clojure doesn't have CL-style compiler-macros either although you can use inlines to emulate them

bronsa19:09:12

yeah that's a bit scary as it doesn't really respects the same semantics as normal clojure, although probably for 96% of the cases it doesn't matter

bronsa19:09:58

so good call! it's probably what @tristefigure needs

tristefigure19:09:17

thanks, but macrolet is something I decided to avoid ... for now. Actually, i'm experimenting with the idea of a closure that receives its context not when it is created, but when it is called. And since I need to fiddle with the passed arguments in the dark, these special closures need to be macros. @bronsa: In clojure.lang.Compiler source code there is a comment about "//no local macros for now".` https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L6822 Do you know what's the rationale behind this ?

gfredericks19:09:44

> And since I need to fiddle with the passed arguments in the dark what does this mean?

gfredericks19:09:54

you might be able to do that by making special-fn capture the &env, and then read it at runtime from a dynamic var

gfredericks19:09:15

I mean, I know you could do that, I just can't tell for sure that it'd fit what you want

gfredericks19:09:37

I guess special-fn would need to identify b somehow, which is tricky

tristefigure19:09:02

Well I actually have something that almost work

gfredericks19:09:05

if you required it to be listed that'd be easier: (special-fn [a] [b] (+ a b))

tristefigure19:09:13

(sorry for the comments being in french)

tristefigure19:09:59

My only problem being that macro-related problem from above

tristefigure19:09:57

And to get the list of the free variables, I deep walk the code looking for symbols whilst keeping track of let-bound variables.

gfredericks19:09:21

which is error-prone 😕

gfredericks19:09:34

I think tools.analyzer would be the most accurate way to do that

tristefigure19:09:26

Ahaha, I'd like to have something that works as a joke before turning it into ... a serious library 😄

gfredericks19:09:29

definitely do the code-walking thing then; I recommend tree-seq if you aren't already using it