sriram
sriram

Reputation: 9032

What is meant by destructuring in Clojure?

I'm a Java and learning clojure.

What is exactly destructuring in clojure?

I can see this blog saying:

The simplest example of destructuring is assigning the values of a vector.

user=> (def point [5 7])
#'user/point

user=> (let [[x y] point]
         (println "x:" x "y:" y))
x: 5 y: 7

what he meant by assigning the values of a vector? Whats the real use of it?

Thanks in advance

Upvotes: 6

Views: 247

Answers (6)

Aditya
Aditya

Reputation: 83

The term "Destructuring" sounds heavier than it is.

It's like visually matching shapes to shapes. For example:

(def nums [1 2 3 4 5 6])

(let [[a b c & others] nums]
  ;; do something
  )

Imagine the effect of the let binding as:

 1  2  3    4 5 6
 |  |  |   (     )
 v  v  v      v
[a  b  c & others]

;; Now we can use a, b, c, others, and of course nums, 
;; inside the let binding:

user=> (let [[a b c & others] nums] 
         (println a) 
         (println b) 
         (println c) 
         (println others) 
         (println nums))      
 1
 2
 3
 (4 5 6)
 [1 2 3 4 5 6]

The goal is to concisely name items of a collection, for use inside the scope of a let binding or function (i.e. within a "lexical scope").

Why "concise"? Well, without destructuring, the let binding would look like this:

(let [a (nth nums 0) ;; or (first nums)
      b (nth nums 1) ;; or (second nums)
      c (nth nums 2)
      others (drop 3 nums)]
  ;; do something
  )

This illustrates the basic idea. There are many details (ifs and buts, and dos and don'ts), and it's worth reading further, in depth. Here are a few resources that explain more, with examples:

My personal favourite: Jay Fields's post on Clojure Destructuring: http://blog.jayfields.com/2010/07/clojure-destructuring.html

A gentle introduction to destructuring, from Braveclojure: http://www.braveclojure.com/do-things/#3_3_3__Destructuring

Upvotes: 2

Hendekagon
Hendekagon

Reputation: 4643

It means making a picture of the structure of some data with symbols

((fn [[d [s [_ _]]]] 
  (apply str (concat (take 2 (name d)) (butlast (name s)) (drop 7 (name d))) ))     
   '(describing (structure (of data))))

=> "destructuring"

((fn [[d e _ _ _ _ _ i n g _ _ _ _ _ s t r u c t u r e & etc]] 
  [d e s t r u c t u r i n g]) "describing the structure of data")

=> [\d \e \s \t \r \u \c \t \u \r \i \n \g]

Paste those ^ examples into a REPL & play around with them to see how it works.

Upvotes: 2

Thumbnail
Thumbnail

Reputation: 13473

Destructuring binds a pattern of names to a complex object by binding each name to the corresponding part of the object.

To bind to a sequence, you present a vector of names. For example ...

(let [[x y] (list 5 7)] ... )

... is equivalent to

(let [x 5, y 7] ... )

To bind to a map or to a vector by index lookup, you present a map of name-to-key pairs. For example ...

(let [{x 0, y 1} [5 7]] ... )

... is equivalent to both of the above.

As others have mentioned, you can find a full description of this powerful mechanism here.

Upvotes: 0

Daniel Dinnyes
Daniel Dinnyes

Reputation: 5017

Destructuring is a convenience feature which allows local bindings (not variables!) to be created easily by taking apart complex data structures (seq-ables like vectors, or associatives like hash-maps), as it is described here.

Take the following example:

(let [v [1 2 3 4 5 6]
      v_0 (first v)
      v_1 (nth v 1)
      v_rest (drop 2 v) 
      m {:a 1 :b 2}
      m_a (get m :a)
      m_b (get m :b)
      m_default (get m :c "DEFAULT")]
  (println v, v_0, v_1, v_rest, m, m_a, m_b, m_default))

Then the above code can be simplified using destructuring bindings like the following:

(let [[v_0 v_1 & v_rest :as v]
      [1 2 3 4 5 6]
      {m_a :a m_b :b m_default :c :or {m_default "DEFAULT"} :as m}
      {:a 1 :b 2}]
  (println v, v_0, v_1, v_rest, m, m_a, m_b, m_default))

Destructuring patterns can be used in let bindings and function parameters (fn, defn, letfn, etc.), and also in macros to return let bindings containing such destructuring patterns.

One important usage to note is with the if-letand when-let macros. The if statement is always evaluated on the whole form, even if the destructured bindings themselves evaluate to nil:

(if-let [{:keys [a b]}
        {:c 1 :d 2}]
  (println a b)
  (println "Not this one"))

Upvotes: 0

Shlomi
Shlomi

Reputation: 4748

its used to name components of a data structure, and get their values.

Say you want to have a "person" structure. In java, you would go all the way to create a class with constructors, getters and setters for the various fields, such as name, age, height etc.

In Clojure you could skip the "ceremony" and simply have a vector with 3 slots, first for name, than for age and last for height. Now you could simply name these "components" and get their values, like so:

(def person ["Fred" 30 180])
(let [[name age height] person]
  (println name age height))    ;; will print: Fred 30 180

p.s - there are better ways to make a "person" in clojure (such as records etc), this is just an example to understand what destructuring does.

Upvotes: 0

Barmar
Barmar

Reputation: 780974

point is a variable that contains a vector of values. [x y] is a vector of variable names.

When you assign point to [x y], destructuring means that the variables each get assigned the corresponding element in the value.

This is just a simpler way of writing:

(let [x (nth point 0) y (nth point 1)]
    (println "x:" x "y:" y))

See Clojure let binding forms for another way to use destructuring.

Upvotes: 2

Related Questions