2016-12-07 4 views
0

Я просматривал некоторые Clojure source code и наткнулся на эту функцию:Как разобрать вложенные параметры в Clojure defn?

(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"}])) 

То, что я не понимаю, как [app-state [r c]] разбирается. Какова бы типичная структура данных была передана этому и как дефнексировать ее. Любые ссылки на это в документах clojure будут оценены, особенно с ClojureDocs.org was of no help on the subject.

+0

IIRC, все подрывающий использует 'deconstruct' (или что-то подобное) макрокоманды. Он просто превращает его в вызовы 'first',' rest' и 'nth' для списков и делегирует аксессуар для карт. Просто типичная макроса «магия». – Carcigenicate

+1

Слово для этого - «деструктурирование» - использование этого должно помочь вам найти хорошую документацию, такую ​​как http://clojure.org/guides/destructuring –

+0

... откровенно говоря, я думаю, что описание того, как деструктурирующие работы * вообще * (как я это читаю) слишком широка, чтобы быть хорошим вопросом StackOverflow - если вы посмотрите на страницу деструктурирования, связанную выше, есть гораздо больше контента, чем то, что может разумно покрыть ответ! –

ответ

2

Функция draw-mask в вашем примере принимает два аргумента. Первый - app-state, который не используется в вашем коде, а второй может быть одним из нескольких разных типов данных: значениями из карты, строкой, списком или, чаще всего, вектором. Здесь вы можете увидеть различные типы, которые могут использоваться в nthFrom в clojure code.

Это называется последовательным destructuring, и, как упоминалось выше, это большая тема. Тем не менее, для вашего случая, это то, как он работает:

(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 

Одно уточнение здесь: действительно ли структура seqable? не является основным критерием для возможности быть деструктурированный. Например, set - seqable?, но не может быть разрушен. Основные критерии для последовательный деструктурирование (отличное от ассоциативного деструктурирования с использованием карт, которое здесь не обсуждается) заключается в том, что на нем должно поддерживаться nth. В RT.java вы увидите список возможных типов. Это: CharSequence, родной Java-массив, RandomAccess, Matcher, Map.Entry и Sequential (Sequential будет охватывать наиболее распространенные структуры: список и вектор).

3

Коррекция

Как @Josh указывает, последовательный деструктурирующий требует nth работы: seqability не достаточно.


Это простой случай sequential destructuring. Давайте использовать функцию, которая показывает, что происходит:

(defn foo [app-state [r c]] 
{:app-state app-state, :r r, :c c}) 
  • Первый аргумент, app-state, может быть что угодно.
  • Второй аргумент, [r c], должен быть чем-то вроде последовательности, к которой относится nth. Затем
    • r является его first элементом, а
    • c является его вторым.
  • Если последовательность не достаточно длинная, они дают nil.

Примеры:

(foo 1()) 
;{:app-state 1, :r nil, :c nil} 

(foo inc "hello, world!") 
;{:app-state #<core$inc [email protected]>, :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} 

Но

(foo 99 #{1 2}) 
;java.lang.UnsupportedOperationException: nth not supported on this type: PersistentHashSet 
; ... 
Смежные вопросы