Doh!  Major face palm.  I had such a bad case of tunnel vision on the macro
definition I forgot to look up the stack once I'd fixed the macro.  Thanks.
 Good to have extra eyes.


On Mon, Jul 21, 2014 at 1:04 PM, Matthew DeVore <matv...@gmail.com> wrote:

> 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> 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
>>>
>>> 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
>>>
>>> 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.
>>>
>>> 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 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+unsubscr...@googlegroups.com.
> 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.

Reply via email to