I haven't taken the time to fully grok your macro, but the error is not the fault of your macro, but of the function invocation. (foo x) is causing the error because x is undefined. foo is a plain function, not a macro, so it tries to evaluate each argument. (foo 'x) works fine for me, as does (let [x 42] (foo x))
I guess the fact that (foo x) recycled the name of the parameter used in the function definition is what made the error message confusing? On Monday, July 21, 2014 9:49:10 AM UTC-7, Dave Tenny wrote: > > In my case, I'm trying to use a the expression '[x] that is available to > the macro in the resulting product. So I don't want the value of x at all, > just a vector with the symbol x. > > That vector is in a variable I have in the macro named > 'positional-parameters', so I substitute '~positional-parameters to with > the hope of getting '[x] in the resulting definition. > > Here's a fragment of the overall defs. As you can see I'm just messing > around, I was trying to write a defun with 'supplied-p' lambda list > semantics, and my clojure/macrology is awful. It's the macro near the > bottom. You can append this to > https://github.com/dtenny/clojdt/blob/master/src/jdt/cl.clj if you want > to git clone and compile it. > > (def lambda-list-keyword-symbols > "Symbols without namespace specifications" > (into #{} (map symbol ["&allow-other-keys" "&key" "&rest" "&aux" > "&optional"]))) > > (defn lambda-list-keyword? > "If x is a lambda list keyword, in any case, return the canonicalized > form as a symbol. > If it starts with an ampersand but is not a valid lambda list keyword, > throw an exception." > [x] > (let [sym-name (.toLowerCase (name x))] > (if (= (first sym-name) \&) > (if-let [lambda-sym (lambda-list-keyword-symbols (symbol sym-name))] > lambda-sym > (throw (Exception. (str "'" x "' is not a valid lambda list > keyword.")))) > nil))) > > (defn lambda-list-segment > "Return three values in a vector. > > The first value is a vector of non-lambda-list-keywords > in l before the next lambda list keyword in the list. Order is > preserved. > > The second value is the canonicalized lambda list keyword (as a clojure > symbol, e.g. '&aux) > that terminated accumulation, or nil if we reached the end of the list. > > The third value is the rest of the list following the lambda list > keyword, or nil if there aren't > any more values. > > E.g. (lambda-list-segment '(a b &optional c)) > => [[a b] &optional (c)]" > [l] > (loop [result [] l l] > (if (empty? l) > [result nil nil] > (let [head (first l) > tail (rest l) > lambda-keyword (lambda-list-keyword? head)] > (if lambda-keyword > [result lambda-keyword tail] > (recur (conj result head) tail)))))) > > (defn partition-lambda-list > "Return a map keyed by lambda list keyword (or the pseudo keyword > '&positional' > for positional args), and valued by a vector lambda vars associated > with the > type of lambda list element, in the order specified by the caller. > E.g. (partition-lambda-list [a b c &optional (d nil d-supplied-p) &key > e]) > => {&positional [a b c] &optional [(d nil d-supplied-p)] &key [e]} > Ignore case in things appearing to be lambda list keywords. > Complain if any symbol begins with an ampersand and is not a valid > lambda list keyword. > Preserve order of parameters." > [lambda-list] > (let [first-chunk (lambda-list-segment lambda-list) > positionals (first first-chunk)] > (loop [result {'&positional positionals} > next-lambda-key (second first-chunk) > lambda-list (nth first-chunk 2)] > (if (empty? lambda-list) > (if next-lambda-key > (merge result {next-lambda-key []}) ; in case it's > &allow-other-keys > result) > (let [chunk (lambda-list-segment lambda-list)] > (recur (merge result {next-lambda-key (first chunk)}) > (second chunk) > (nth chunk 2))))))) > > (defn parse-defun-decls > "Parse defun elements following the lambda list. > If there are declarations, strip them from the sequence. > Return a vector of two things. > 1) the docstring, or nil if there isn't one. > 2) forms following the optional declarations and docstring, nil if > there aren't any." > [s] > (let [declare? (fn [l] > (and (list? l) > (.equalsIgnoreCase (name (first l)) "declare")))] > (loop [s s] > (if (empty? s) > [nil nil] > (let [head (first s)] > (cond (string? head) [head (rest s)] ; **BUG** won't work if > declare is after docstring > (declare? head) (recur (rest s)) > :else [nil s])))))) > > (defn positional-values > "Given a sequence of formal parameter names for positional values > and a sequence of actual arguments to a defun'ed function call, > return a vector of values from actual args to be bound to parameters. > Return [] if there aren't any." > [parameters actual-args] > (if parameters > (if (< (count actual-args) (count parameters)) > (throw (Exception. (str "Insufficient arguments in " actual-args > " to match positional parameters in " > parameters))) > (loop [values [] args actual-args] > (if (empty? args) > values > (recur (conj values (first args)) (rest args))))) > [])) > > ;; *FINISH*: define/support RETURN-FROM > > (defmacro defun > "defun function-name lambda-list [[declaration* | documentation]] form* > => function-name > Arguments and Values: > function-name---a function name. > lambda-list---an ordinary lambda list. > declaration---a declare expression that is discarded. > documentation---a string; not evaluated. > forms---an implicit progn. > > Notes: > This is meant to be as common-lisp oriented as possible in a clojure > environment. > Thus a function definition is (defun foo (&optional bar) ...) > and NOT (defun foo [clojure-y args] ...)" > [function-name lambda-list & decls-doc-forms] > (let [param-map (partition-lambda-list lambda-list) > [docstring forms] (parse-defun-decls decls-doc-forms) > args-var (gensym "args") > positional-parameters (get param-map '&positional)] > (if docstring > (comment ; *FINISH* docstring variant > ;; `(defn ~function-name ~docstring [& ~args-var] > ;; (let [~@(lambda-list-bindings param-map args-var)] > ;; ~@forms)) > ) > `(defn ~function-name [& ~args-var] > ;; *FINISH*: other param types once we get positional values > working > (let [~positional-parameters (#_positional-values print > '~positional-parameters ~args-var)] > ~@forms))))) > > (println (macroexpand-1 '(defun foo (x) (println x)))) > ;(println (macroexpand '(defun foo (x) (println x)))) > (defun foo (x) (println x)) > (foo x) ; <<<---- generates the error > > > > > > On Sun, Jul 20, 2014 at 5:46 PM, Matthew DeVore <mat...@gmail.com > <javascript:>> wrote: > >> I don't have a Clojure REPL handy at the moment but it looks like the x >> symbol is being resolved in the macro context rather than the expansion >> context. In the macro source, where you have a plain x, try to replace it >> with ~'x ... This blog post may be relevant: >> http://amalloy.hubpages.com/hub/Unhygenic-anaphoric-Clojure-macros-for-fun-and-profit >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@googlegroups.com >> <javascript:> >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com <javascript:> >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to a topic in the >> Google Groups "Clojure" group. >> To unsubscribe from this topic, visit >> https://groups.google.com/d/topic/clojure/grxYLrjnz60/unsubscribe. >> To unsubscribe from this group and all its topics, send an email to >> clojure+u...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.