Clojure

for macro does not allow :let clause in first position

Details

  • Type: Enhancement Enhancement
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Declined
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Patch:
    Code and Test

Description

I like to try and keep my level of nesting under control, and this
often involves hiding or re-structuring the let macro. The for macro
can implicitly assemble a let macro for you, but with a limitation
that the :let clause can't be first:

1:5 user=> (for [:let [z [:foo :bar]] x z] (name x))
java.lang.IllegalStateException: Can't pop empty vector (repl-1:5)
1:6 user=> (for [x [:foo :bar] :let [z (name x)]] z)
("foo" "bar")
1:7 user=>

Is this limitation intentional? Could the error message be improved?

Here's what I wanted to write:

(defn add-script-links-for-imported-javascript-libraries
       [env dom-nodes]
       (extend-dom dom-nodes [:html :head] :top
               (template-for [:let [aggregation (-> env :cascade :resource-aggregation)
                                         libraries (@aggregation :libraries)]
                                   asset-map libraries
                                   :let [path (to-asset-path env asset-map)]]
                       :script { :type "text/javascript" :src path } [ linebreak ])))

(the formatting is probably scrambled)

But I had to juggle it to this:

(defn add-script-links-for-imported-javascript-libraries
       [env dom-nodes]
       (let [aggregation (-> env :cascade :resource-aggregation)
              libraries (@aggregation :libraries)]
               (extend-dom dom-nodes [:html :head] :top
                       (template-for [asset-map libraries
                                           :let [path (to-asset-path env asset-map)]]
                               :script { :type "text/javascript" :src path } [ linebreak ]))))

Of course there are any number of ways to write this, but I prefer the
first option, as it does less of a job of obscuring what the main
point of the function is: a call to extend-dom.

Activity

Hide
Assembla Importer added a comment -
Show
Assembla Importer added a comment - Converted from http://www.assembla.com/spaces/clojure/tickets/207
Hide
Tassilo Horn added a comment -

The attached patch implements that feature and also adds tests for it. The new tests and all other tests still pass.

The patch exploits the fact that

(for [:let [a 1, b [1 2]], c [1 2 3]] ...)

is equivalent to

(for [a [1], b [[1 2]], c [1 2 3]] ...)

and thus transforms the former binding vector to the latter.

Show
Tassilo Horn added a comment - The attached patch implements that feature and also adds tests for it. The new tests and all other tests still pass. The patch exploits the fact that
(for [:let [a 1, b [1 2]], c [1 2 3]] ...)
is equivalent to
(for [a [1], b [[1 2]], c [1 2 3]] ...)
and thus transforms the former binding vector to the latter.
Hide
Rich Hickey added a comment -

just put the for in a let please

Show
Rich Hickey added a comment - just put the for in a let please
Hide
Carl Smotricz added a comment -

I came here to report this as a bug.

I respect Rich's decision to disallow :let at the beginning of a (for), of course, but I feel that if the syntax is to be declared illegal then the compiler should report an error rather than explode with an exception.

Thus I suggest catching the error in the compiler and reporting it as a syntax error.

Show
Carl Smotricz added a comment - I came here to report this as a bug. I respect Rich's decision to disallow :let at the beginning of a (for), of course, but I feel that if the syntax is to be declared illegal then the compiler should report an error rather than explode with an exception. Thus I suggest catching the error in the compiler and reporting it as a syntax error.

People

  • Assignee:
    Unassigned
    Reporter:
    Anonymous
Vote (1)
Watch (2)

Dates

  • Created:
    Updated:
    Resolved: