How to parse nested parameters in a Clojure defn?
I was browsing some Clojure source code and came across this function:
(defn draw-mask [app-state [r c]]
(let [x1 (+ 25 (* c 50))
y1 (+ 25 (* r 50))]
[:circle {:cx x1 :cy y1 :r 12 :fill "white"}]))
What I do not understand is how [app-state [rc]]
is parsed. What would a typical data structure passed to this and how does defn parcel it out. Any references to this in the clojure docs would be appreciated, especially since ClojureDocs.org was of no help on the subject.
The function draw-mask
in your example takes two arguments. The first is app-state
, which is not used in your code, and the second can be one of several different types of data: values from a map, a string, a list, or most commonly, a vector. You can see the different types here that can be used in nthFrom
in the clojure code.
This is called sequential destructuring, and as other comments above mention, it's a big topic. However, for your case, this is how it works:
(draw-mask xyz [3 9]) ---> In draw-mask, r is 3, and c is 9.
(draw-mask xyz [3]) ---> In draw-mask, r is 3, and c is nil.
(draw-mask xyz [3 9 12]) ---> In draw-mask, r is 3, and c is 9 -- 12 is not bound
One clarification here: whether or not a structure is seqable?
is not the main criteria for being able to be destructured. For example, a set
is seqable?
but cannot be destructured. The main criteria for sequential destructuring (different from associative destructuring, using maps, which is not discussed here) is that nth
must be supported on it. In RT.java, you will see the list of possible types. They are: CharSequence
, a native Java array, RandomAccess
, Matcher
, Map.Entry
, and Sequential
( Sequential
will cover the most common structures: list and vector).
Correction
As @Josh points out, sequential destructuring requires nth
to work: seqability is not enough.
This is a simple case of sequential destructuring. Let's use a function that shows what's going on:
(defn foo [app-state [r c]]
{:app-state app-state, :r r, :c c})
app-state
, can be anything. [rc]
, must be something like a sequence that nth
applies to. Then r
is its first
element, and c
is its second. nil
. Examples:
(foo 1 ())
;{:app-state 1, :r nil, :c nil}
(foo inc "hello, world!")
;{:app-state #<core$inc clojure.core$inc@32d23c2f>, :r h, :c e}
(foo :one [:two :three :four])
;{:app-state :one, :r :two, :c :three}
(foo "Flubalub" (drop 5 (iterate #(* 10 %) 1)))
;{:app-state "Flubalub", :r 100000, :c 1000000}
But
(foo 99 #{1 2})
;java.lang.UnsupportedOperationException: nth not supported on this type: PersistentHashSet
; ...
链接地址: http://www.djcxy.com/p/82580.html
下一篇: 如何解析Clojure定义中的嵌套参数?