Skip to content

Instantly share code, notes, and snippets.

@joey-coleman
Forked from john2x/00_destructuring.md
Created November 23, 2015 20:51

Revisions

  1. @john2x john2x revised this gist Sep 26, 2014. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion 01_compojure.md
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,6 @@ Here, the request map will be bound to the `request` var and when `my-handler` i
    ```clojure
    (defn my-handler [request] ...)
    ;; ___________________
    ;; | |
    ;; | V
    (GET "/some/path" request (my-handler request))
    ```
  2. @john2x john2x revised this gist Sep 26, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 01_compojure.md
    Original file line number Diff line number Diff line change
    @@ -18,7 +18,7 @@ Here, the request map will be bound to the `request` var and when `my-handler` i
    (defn my-handler [request] ...)
    ;; ___________________
    ;; | |
    ;; | v
    ;; | V
    (GET "/some/path" request (my-handler request))
    ```

  3. @john2x john2x revised this gist Sep 26, 2014. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions 01_compojure.md
    Original file line number Diff line number Diff line change
    @@ -16,6 +16,9 @@ Here, the request map will be bound to the `request` var and when `my-handler` i

    ```clojure
    (defn my-handler [request] ...)
    ;; ___________________
    ;; | |
    ;; | v
    (GET "/some/path" request (my-handler request))
    ```

  4. @john2x john2x revised this gist Sep 20, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 01_compojure.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ Compojure Destructuring
    The basic syntax of a Compojure route is as follows:

    ```
    (REQUEST-METHOD "/path" params-passed-to-handler-fn (handler-fn params-passed-to-handler-fn))
    (REQUEST-METHOD "/path" request-data (handler-fn request-data))
    ```

    The simplest form is to pass the entire [Ring request map][ring-request-map] to your handler function.
  5. @john2x john2x revised this gist Sep 20, 2014. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions 00_destructuring.md
    Original file line number Diff line number Diff line change
    @@ -76,6 +76,12 @@ You can use both `& the-rest` and `:as some-symbol`.
    With destructuring and the `& the-rest` form, you can specify optional arguments to functions.

    ```clojure
    (defn foo [a b & more-args]
    (println a b more-args))
    (foo :a :b) ;; => :a :b nil
    (foo :a :b :x) ;; => :a :b (:x)
    (foo :a :b :x :y :z) ;; => :a :b (:x :y :z)

    (defn foo [a b & [x y z]]
    (println a b x y z))
    (foo :a :b) ;; => :a :b nil nil nil
  6. @john2x john2x revised this gist Sep 20, 2014. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions 00_destructuring.md
    Original file line number Diff line number Diff line change
    @@ -31,11 +31,11 @@ You don't have to match the full vector.
    ;; => :a :b :c
    ```

    You can use `& rest` to bind the remaining part of the vector to `rest`. (Although note that `rest` is a core function, so you might want to use a different symbol in real code)
    You can use `& the-rest` to bind the remaining part of the vector to `the-rest`.

    ```clojure
    (let [[a b & rest] my-vector]
    (println a b rest))
    (let [[a b & the-rest] my-vector]
    (println a b the-rest))
    ;; => :a :b (:c :d)
    ```

    @@ -63,17 +63,17 @@ You can use `:as some-symbol` as the *last two items* in the destructuring form
    ;; => :a :x :y :z [:x :y :z] [:a :b :c :d [:x :y :z]]
    ```

    You can use both `& rest` and `:as some-symbol`.
    You can use both `& the-rest` and `:as some-symbol`.

    ```clojure
    (let [[a b & rest :as all] my-vector]
    (println a b rest all))
    (let [[a b & the-rest :as all] my-vector]
    (println a b the-rest all))
    ;; => :a :b (:c :d) [:a :b :c :d]
    ```

    ### Optional arguments for functions

    With destructuring and the `& rest` form, you can specify optional arguments to functions.
    With destructuring and the `& the-rest` form, you can specify optional arguments to functions.

    ```clojure
    (defn foo [a b & [x y z]]
    @@ -133,7 +133,7 @@ And combining `:as` and `:or` keywords (again, `:as` preferred to be the last).
    ;; => A B :) {:a A :b B :c C :d D}
    ```

    There is no `& rest` for maps.
    There is no `& the-rest` for maps.

    ### Shortcuts

  7. @john2x john2x revised this gist Sep 20, 2014. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions 01_compojure.md
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,7 @@ Since the request is just a regular Clojure map, Compojure allows you to destruc
    (println query-string))

    (GET "/some/path" {uri :uri, query-string :query-string} (my-handler uri query-string))
    ;; or
    ;; or with the shortcuts
    (GET "/some/path" {:keys [uri query-string]} (my-handler uri query-string))
    ```

    @@ -53,7 +53,7 @@ The `wrap-params` middleware parses the value of `:query-string` and inserts it

    From here, assume that all handlers are wrapped with `wrap-params`.


    (I got sleepy)

    [compojure]: https://github.com/weavejester/compojure/wiki/Destructuring-Syntax
    [ring-request-map]: https://github.com/ring-clojure/ring/wiki/Concepts#requests
  8. @john2x john2x revised this gist Sep 20, 2014. 2 changed files with 0 additions and 0 deletions.
    File renamed without changes.
    File renamed without changes.
  9. @john2x john2x revised this gist Sep 20, 2014. 2 changed files with 60 additions and 6 deletions.
    60 changes: 60 additions & 0 deletions compojure.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    Compojure Destructuring
    =======================

    [Official docs][compojure]

    The basic syntax of a Compojure route is as follows:

    ```
    (REQUEST-METHOD "/path" params-passed-to-handler-fn (handler-fn params-passed-to-handler-fn))
    ```

    The simplest form is to pass the entire [Ring request map][ring-request-map] to your handler function.

    Here, the request map will be bound to the `request` var and when `my-handler` is called it is passed as an argument. You can then extract/manipulate whatever data you want in the `request` map:


    ```clojure
    (defn my-handler [request] ...)
    (GET "/some/path" request (my-handler request))
    ```

    Since the request is just a regular Clojure map, Compojure allows you to destructure that map using the same map destructuring methods above. This is useful if you only want specific values from the map for the handler function to work with:

    ```clojure
    (defn my-handler [uri query-string]
    (println uri)
    ;; note that query-string is raw. e.g. "foo=bar&fizz=buzz"
    (println query-string))

    (GET "/some/path" {uri :uri, query-string :query-string} (my-handler uri query-string))
    ;; or
    (GET "/some/path" {:keys [uri query-string]} (my-handler uri query-string))
    ```

    If you want to pass the entire request map as well:

    ```clojure
    (defn my-handler [uri query-string request]
    (println request)
    (println uri)
    (println query-string))

    (GET "/some/path" {:keys [uri query-string] :as request} (my-handler uri query-string request))
    ```

    Compojure-specific Destructuring
    --------------------------------

    Since regular destructuring can be quite verbose, Compojure offers a more specialised form of destructuring. If you supply a vector, Compojure will use this custom destructuring syntax [1][compojure].

    **Note:** This only works for routes wrapped with the [`wrap-params` middleware][wrap-params]. This is because by default, a [Ring request map][ring-request-map] doesn't include the `:params` entry (which contains the parsed value of `:query-string`).
    The `wrap-params` middleware parses the value of `:query-string` and inserts it into the request map as `:params`, which Compojure's special destructuring syntax targets. (TODO: Ring wiki is old. Is this still true?)

    From here, assume that all handlers are wrapped with `wrap-params`.



    [compojure]: https://github.com/weavejester/compojure/wiki/Destructuring-Syntax
    [ring-request-map]: https://github.com/ring-clojure/ring/wiki/Concepts#requests
    [wrap-params]: https://github.com/ring-clojure/ring/wiki/Parameters
    6 changes: 0 additions & 6 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -206,9 +206,3 @@ Here be dragons.

    **TODO**

    * * *

    Compojure
    ---------

    **TODO**
  10. @john2x john2x revised this gist Aug 3, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion destructuring.md
    Original file line number Diff line number Diff line change
    @@ -31,7 +31,7 @@ You don't have to match the full vector.
    ;; => :a :b :c
    ```

    You can use `& rest` to bind the remaining part of the vector to `rest`.
    You can use `& rest` to bind the remaining part of the vector to `rest`. (Although note that `rest` is a core function, so you might want to use a different symbol in real code)

    ```clojure
    (let [[a b & rest] my-vector]
  11. @john2x john2x revised this gist Jul 27, 2014. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,8 @@
    Clojure Destructuring Tutorial and Cheat Sheet
    ==============================================

    ([Related blog post](http://john2x.com/blog/clojure-destructuring))

    Simply put, destructuring in Clojure is a way extract values from a datastructure and bind them to symbols, without having to explicitly traverse the datstructure. It allows for elegant and concise Clojure code.

    Vectors
  12. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -79,6 +79,7 @@ With destructuring and the `& rest` form, you can specify optional arguments to
    (foo :a :b) ;; => :a :b nil nil nil
    (foo :a :b :x) ;; => :a :b :x nil nil
    (foo :a :b :x :y :z) ;; => :a :b :x :y :z
    ```

    Maps
    ----
    @@ -96,6 +97,7 @@ Maps
    (let [{a :a, b :b, {x :x, y :y} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y
    ```

    Similar to vectors, if a key is not found in the map, the symbol will be bound to `nil`.

  13. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 115 additions and 86 deletions.
    201 changes: 115 additions & 86 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -9,104 +9,125 @@ Vectors
    **Syntax:** `[symbol another-symbol] ["value" "another-value"]`

    ```clojure
    (def my-vector [:a :b :c :d])
    (def my-nested-vector [:a :b :c :d [:x :y :z]])
    (def my-vector [:a :b :c :d])
    (def my-nested-vector [:a :b :c :d [:x :y :z]])

    (let [[a b c d] my-vector]
    (println a b c d))
    ;; => :a :b :c :d
    (let [[a b c d] my-vector]
    (println a b c d))
    ;; => :a :b :c :d

    (let [[a _ _ d [x y z]] my-nested-vector]
    (println a d x y z))
    ;; => :a :d :x :y :z
    (let [[a _ _ d [x y z]] my-nested-vector]
    (println a d x y z))
    ;; => :a :d :x :y :z
    ```

    You don't have to match the full vector.

    (let [[a b c] my-vector]
    (println a b c))
    ;; => :a :b :c
    ```clojure
    (let [[a b c] my-vector]
    (println a b c))
    ;; => :a :b :c
    ```

    You can use `& rest` to bind the remaining part of the vector to `rest`.

    (let [[a b & rest] my-vector]
    (println a b rest))
    ;; => :a :b (:c :d)
    ```clojure
    (let [[a b & rest] my-vector]
    (println a b rest))
    ;; => :a :b (:c :d)
    ```

    When a destructuring form "exceeds" a vector (i.e. there not enough items in the vector to bind to), the excess symbols will be bound to `nil`.

    (let [[a b c d e f g] my-vector]
    (println a b c d e f g))
    ;; => :a :b :c :d nil nil nil
    ```clojure
    (let [[a b c d e f g] my-vector]
    (println a b c d e f g))
    ;; => :a :b :c :d nil nil nil
    ```

    You can use `:as some-symbol` as the *last two items* in the destructuring form to bind the whole vector to `some-symbol`

    (let [[:as all] my-vector]
    (println all))
    ;; => [:a :b :c :d]
    ```clojure
    (let [[:as all] my-vector]
    (println all))
    ;; => [:a :b :c :d]

    (let [[a :as all] my-vector]
    (println a all))
    ;; => :a [:a :b :c :d]
    (let [[a :as all] my-vector]
    (println a all))
    ;; => :a [:a :b :c :d]

    (let [[a _ _ _ [x y z :as nested] :as all] my-nested-vector]
    (println a x y z nested all))
    ;; => :a :x :y :z [:x :y :z] [:a :b :c :d [:x :y :z]]
    (let [[a _ _ _ [x y z :as nested] :as all] my-nested-vector]
    (println a x y z nested all))
    ;; => :a :x :y :z [:x :y :z] [:a :b :c :d [:x :y :z]]
    ```

    You can use both `& rest` and `:as some-symbol`.

    (let [[a b & rest :as all] my-vector]
    (println a b rest all))
    ;; => :a :b (:c :d) [:a :b :c :d]
    ```clojure
    (let [[a b & rest :as all] my-vector]
    (println a b rest all))
    ;; => :a :b (:c :d) [:a :b :c :d]
    ```

    ### Optional arguments for functions

    With destructuring and the `& rest` form, you can specify optional arguments to functions.

    (defn foo [a b & [x y z]]
    (println a b x y z))
    (foo :a :b) ;; => :a :b nil nil nil
    (foo :a :b :x) ;; => :a :b :x nil nil
    (foo :a :b :x :y :z) ;; => :a :b :x :y :z
    ```clojure
    (defn foo [a b & [x y z]]
    (println a b x y z))
    (foo :a :b) ;; => :a :b nil nil nil
    (foo :a :b :x) ;; => :a :b :x nil nil
    (foo :a :b :x :y :z) ;; => :a :b :x :y :z

    Maps
    ----

    **Syntax:** `{symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}`

    (def my-hashmap {:a "A" :b "B" :c "C" :d "D"})
    (def my-nested-hashmap {:a "A" :b "B" :c "C" :d "D" :q {:x "X" :y "Y" :z "Z"}})
    ```clojure
    (def my-hashmap {:a "A" :b "B" :c "C" :d "D"})
    (def my-nested-hashmap {:a "A" :b "B" :c "C" :d "D" :q {:x "X" :y "Y" :z "Z"}})

    (let [{a :a d :d} my-hashmap]
    (println a d))
    ;; => A D
    (let [{a :a d :d} my-hashmap]
    (println a d))
    ;; => A D

    (let [{a :a, b :b, {x :x, y :y} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y
    (let [{a :a, b :b, {x :x, y :y} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y

    Similar to vectors, if a key is not found in the map, the symbol will be bound to `nil`.

    (let [{a :a, not-found :not-found, b :b} my-hashmap]
    (println a not-found b))
    ;; => A nil B
    ```clojure
    (let [{a :a, not-found :not-found, b :b} my-hashmap]
    (println a not-found b))
    ;; => A nil B
    ```

    You can provide an optional default value for these missing keys with the `:or` keyword and a map of default values.

    (let [{a :a, not-found :not-found, b :b, :or {not-found ":)"}} my-hashmap]
    (println a not-found b))
    ;; => A :) B
    ```clojure
    (let [{a :a, not-found :not-found, b :b, :or {not-found ":)"}} my-hashmap]
    (println a not-found b))
    ;; => A :) B
    ```

    The `:as some-symbol` form is also available for maps, but unlike vectors it can be specified anywhere (but still preferred to be the last two pairs).

    (let [{a :a, b :b, :as all} my-hashmap]
    (println a b all))
    ;; => A B {:a A :b B :c C :d D}
    ```clojure
    (let [{a :a, b :b, :as all} my-hashmap]
    (println a b all))
    ;; => A B {:a A :b B :c C :d D}
    ```

    And combining `:as` and `:or` keywords (again, `:as` preferred to be the last).

    (let [{a :a, b :b, not-found :not-found, :or {not-found ":)"}, :as all} my-hashmap]
    (println a b not-found all))
    ;; => A B :) {:a A :b B :c C :d D}
    ```clojure
    (let [{a :a, b :b, not-found :not-found, :or {not-found ":)"}, :as all} my-hashmap]
    (println a b not-found all))
    ;; => A B :) {:a A :b B :c C :d D}
    ```

    There is no `& rest` for maps.

    @@ -116,55 +137,63 @@ Having to specify `{symbol :symbol}` for each key is repetitive and verbose (it'

    Here are all the previous examples using the `:keys` keyword followed by a vector of symbols:

    (let [{:keys [a d]} my-hashmap]
    (println a d))
    ;; => A D
    ```clojure
    (let [{:keys [a d]} my-hashmap]
    (println a d))
    ;; => A D

    (let [{:keys [a b], {:keys [x y]} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y
    (let [{:keys [a b], {:keys [x y]} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y

    (let [{:keys [a not-found b]} my-hashmap]
    (println a not-found b))
    ;; => A nil B
    (let [{:keys [a not-found b]} my-hashmap]
    (println a not-found b))
    ;; => A nil B

    (let [{:keys [a not-found b], :or {not-found ":)"}} my-hashmap]
    (println a not-found b))
    ;; => A :) B
    (let [{:keys [a not-found b], :or {not-found ":)"}} my-hashmap]
    (println a not-found b))
    ;; => A :) B

    (let [{:keys [a b], :as all} my-hashmap]
    (println a b all))
    ;; => A B {:a A :b B :c C :d D}
    (let [{:keys [a b], :as all} my-hashmap]
    (println a b all))
    ;; => A B {:a A :b B :c C :d D}

    (let [{:keys [a b not-found], :or {not-found ":)"}, :as all} my-hashmap]
    (println a b not-found all))
    ;; => A B :) {:a A :b B :c C :d D}
    (let [{:keys [a b not-found], :or {not-found ":)"}, :as all} my-hashmap]
    (println a b not-found all))
    ;; => A B :) {:a A :b B :c C :d D}
    ```

    There are also `:strs` and `:syms` alternatives, for when your map has strings or symbols for keys (instead of keywords), respectively.

    (let [{:strs [a d]} {"a" "A", "b" "B", "c" "C", "d" "D"}]
    (println a d))
    ;; => A D
    ```clojure
    (let [{:strs [a d]} {"a" "A", "b" "B", "c" "C", "d" "D"}]
    (println a d))
    ;; => A D

    (let [{:syms [a d]} {'a "A", 'b "B", 'c "C", 'd "D"}]
    (println a d))
    ;; => A D
    (let [{:syms [a d]} {'a "A", 'b "B", 'c "C", 'd "D"}]
    (println a d))
    ;; => A D
    ```

    ### Keyword arguments for function

    Map destructuring also works with lists (but not vectors).

    (let [{:keys [a b]} '("X", "Y", :a "A", :b "B")]
    (println a b))
    ;; => A B
    ```clojure
    (let [{:keys [a b]} '("X", "Y", :a "A", :b "B")]
    (println a b))
    ;; => A B
    ```

    This allows your functions to have optional keyword arguments.

    (defn foo [a b & {:keys [x y]}]
    (println a b x y))
    (foo "A" "B") ;; => A B nil nil
    (foo "A" "B" :x "X") ;; => A B X nil
    (foo "A" "B" :x "X" :y "Y") ;; => A B X Y
    ```clojure
    (defn foo [a b & {:keys [x y]}]
    (println a b x y))
    (foo "A" "B") ;; => A B nil nil
    (foo "A" "B" :x "X") ;; => A B X nil
    (foo "A" "B" :x "X" :y "Y") ;; => A B X Y
    ```

    More examples
    =============
  14. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@ Vectors

    **Syntax:** `[symbol another-symbol] ["value" "another-value"]`


    ```clojure
    (def my-vector [:a :b :c :d])
    (def my-nested-vector [:a :b :c :d [:x :y :z]])

    @@ -19,7 +19,7 @@ Vectors
    (let [[a _ _ d [x y z]] my-nested-vector]
    (println a d x y z))
    ;; => :a :d :x :y :z

    ```
    You don't have to match the full vector.

    (let [[a b c] my-vector]
  15. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,10 @@
    Clojure Destructuring Tutorial and Cheat Sheet
    ==============================================

    Simply put, destructuring in Clojure is a way extract values from a datastructure and bind them to symbols, without having to explicitly traverse the datstructure. It allows for elegant and concise Clojure code.

    Vectors
    =======
    -------

    **Syntax:** `[symbol another-symbol] ["value" "another-value"]`

    @@ -66,7 +69,7 @@ With destructuring and the `& rest` form, you can specify optional arguments to
    (foo :a :b :x :y :z) ;; => :a :b :x :y :z

    Maps
    ====
    ----

    **Syntax:** `{symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}`

    @@ -172,6 +175,7 @@ Here be dragons.

    * * *

    # Compojure
    Compojure
    ---------

    **TODO**
  16. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    Simply put, destructuring in Clojure is a way extract values from a datastructure and bind them to symbols, without having to explicitly traverse the datstructure. It allows for elegant and concise Clojure code.

    Vectors
    =======

  17. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 7 additions and 1 deletion.
    8 changes: 7 additions & 1 deletion destructuring.md
    Original file line number Diff line number Diff line change
    @@ -147,7 +147,13 @@ There are also `:strs` and `:syms` alternatives, for when your map has strings o

    ### Keyword arguments for function

    With map destructuring, your functions can have optional keyword arguments.
    Map destructuring also works with lists (but not vectors).

    (let [{:keys [a b]} '("X", "Y", :a "A", :b "B")]
    (println a b))
    ;; => A B

    This allows your functions to have optional keyword arguments.

    (defn foo [a b & {:keys [x y]}]
    (println a b x y))
  18. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -137,10 +137,23 @@ Here are all the previous examples using the `:keys` keyword followed by a vecto

    There are also `:strs` and `:syms` alternatives, for when your map has strings or symbols for keys (instead of keywords), respectively.

    (let [{:strs [a d]} {"a" "A", "b" "B", "c" "C", "d" "D"}]
    (println a d))
    ;; => A D

    (let [{:syms [a d]} {'a "A", 'b "B", 'c "C", 'd "D"}]
    (println a d))
    ;; => A D

    ### Keyword arguments for function

    With map destructuring, your functions can have optional keyword arguments.

    (defn foo [a b & {:keys [x y]}]
    (println a b x y))
    (foo "A" "B") ;; => A B nil nil
    (foo "A" "B" :x "X") ;; => A B X nil
    (foo "A" "B" :x "X" :y "Y") ;; => A B X Y

    More examples
    =============
  19. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 32 additions and 8 deletions.
    40 changes: 32 additions & 8 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,7 @@
    Vectors
    =======

    Vector destructuring is the simplest form. It is similar to Python's list unpacking feature, but much more powerful.

    Syntax: `[symbol another-symbol] ["value" "another-value"]`
    **Syntax:** `[symbol another-symbol] ["value" "another-value"]`


    (def my-vector [:a :b :c :d])
    @@ -68,9 +66,7 @@ With destructuring and the `& rest` form, you can specify optional arguments to
    Maps
    ====

    Map destructuring is much more complicated, and can get quite verbose, but is much more powerful than vector destructuring.

    Syntax: `{symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}`
    **Syntax:** `{symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}`

    (def my-hashmap {:a "A" :b "B" :c "C" :d "D"})
    (def my-nested-hashmap {:a "A" :b "B" :c "C" :d "D" :q {:x "X" :y "Y" :z "Z"}})
    @@ -103,15 +99,43 @@ The `:as some-symbol` form is also available for maps, but unlike vectors it can

    And combining `:as` and `:or` keywords (again, `:as` preferred to be the last).

    (let [{a :a, b :b, not-found :not-found :or {not-found ":)"} :as all} my-hashmap]
    (let [{a :a, b :b, not-found :not-found, :or {not-found ":)"}, :as all} my-hashmap]
    (println a b not-found all))
    ;; => A B :) {:a A :b B :c C :d D}

    There is no `& rest` for maps.

    ### Shortcuts

    Having to specify `{symbol :symbol}` for each key is repetitive and verbose (it's almost always going to be the symbol equivalent of the key), so there are shortcuts available so you only have to type the symbol once.
    Having to specify `{symbol :symbol}` for each key is repetitive and verbose (it's almost always going to be the symbol equivalent of the key), so shortcuts are provided so you only have to type the symbol once.

    Here are all the previous examples using the `:keys` keyword followed by a vector of symbols:

    (let [{:keys [a d]} my-hashmap]
    (println a d))
    ;; => A D

    (let [{:keys [a b], {:keys [x y]} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y

    (let [{:keys [a not-found b]} my-hashmap]
    (println a not-found b))
    ;; => A nil B

    (let [{:keys [a not-found b], :or {not-found ":)"}} my-hashmap]
    (println a not-found b))
    ;; => A :) B

    (let [{:keys [a b], :as all} my-hashmap]
    (println a b all))
    ;; => A B {:a A :b B :c C :d D}

    (let [{:keys [a b not-found], :or {not-found ":)"}, :as all} my-hashmap]
    (println a b not-found all))
    ;; => A B :) {:a A :b B :c C :d D}

    There are also `:strs` and `:syms` alternatives, for when your map has strings or symbols for keys (instead of keywords), respectively.



  20. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 11 additions and 11 deletions.
    22 changes: 11 additions & 11 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -55,7 +55,7 @@ You can use both `& rest` and `:as some-symbol`.
    (println a b rest all))
    ;; => :a :b (:c :d) [:a :b :c :d]

    ### Optional arguments for functions:
    ### Optional arguments for functions

    With destructuring and the `& rest` form, you can specify optional arguments to functions.

    @@ -65,10 +65,10 @@ With destructuring and the `& rest` form, you can specify optional arguments to
    (foo :a :b :x) ;; => :a :b :x nil nil
    (foo :a :b :x :y :z) ;; => :a :b :x :y :z

    Hashmaps
    ========
    Maps
    ====

    Hashmap destructuring is much more complicated, and can get quite verbose, but is much more powerful than vector destructuring.
    Map destructuring is much more complicated, and can get quite verbose, but is much more powerful than vector destructuring.

    Syntax: `{symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}`

    @@ -95,7 +95,7 @@ You can provide an optional default value for these missing keys with the `:or`
    (println a not-found b))
    ;; => A :) B

    The `:as some-symbol` form is also available for hashmaps, but unlike vectors it can be specified anywhere (but still preferred to be the last two pairs).
    The `:as some-symbol` form is also available for maps, but unlike vectors it can be specified anywhere (but still preferred to be the last two pairs).

    (let [{a :a, b :b, :as all} my-hashmap]
    (println a b all))
    @@ -107,17 +107,15 @@ And combining `:as` and `:or` keywords (again, `:as` preferred to be the last).
    (println a b not-found all))
    ;; => A B :) {:a A :b B :c C :d D}

    There is no `& rest` for hashmaps.
    There is no `& rest` for maps.

    Shortcuts
    ---------
    ### Shortcuts

    Having to specify `{symbol :symbol}` for each key is repetitive and verbose (it's almost always going to be the symbol equivalent of the key), so there are shortcuts available so you only have to type the symbol once.



    Keyword arguments for functions:
    --------------------------------
    ### Keyword arguments for function


    More examples
    @@ -129,4 +127,6 @@ Here be dragons.

    * * *

    # Compojure
    # Compojure

    **TODO**
  21. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 6 additions and 5 deletions.
    11 changes: 6 additions & 5 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -55,8 +55,7 @@ You can use both `& rest` and `:as some-symbol`.
    (println a b rest all))
    ;; => :a :b (:c :d) [:a :b :c :d]

    Optional arguments for functions:
    ---------------------------------
    ### Optional arguments for functions:

    With destructuring and the `& rest` form, you can specify optional arguments to functions.

    @@ -113,19 +112,21 @@ There is no `& rest` for hashmaps.
    Shortcuts
    ---------

    Having to specify `{symbol :symbol}` is repetitive and verbose (it's almost always going to be the symbol equivalent of the keyword), so there are shortcuts available so you only have to type the symbol once.
    Having to specify `{symbol :symbol}` for each key is repetitive and verbose (it's almost always going to be the symbol equivalent of the key), so there are shortcuts available so you only have to type the symbol once.



    Keyword arguments for functions:
    --------------------------------


    Vectors + Hashmaps + Vectors...
    ===============================
    More examples
    =============

    Here be dragons.

    **TODO**

    * * *

    # Compojure
  22. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 41 additions and 15 deletions.
    56 changes: 41 additions & 15 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -55,8 +55,8 @@ You can use both `& rest` and `:as some-symbol`.
    (println a b rest all))
    ;; => :a :b (:c :d) [:a :b :c :d]

    Function args usage:
    --------------------
    Optional arguments for functions:
    ---------------------------------

    With destructuring and the `& rest` form, you can specify optional arguments to functions.

    @@ -73,33 +73,59 @@ Hashmap destructuring is much more complicated, and can get quite verbose, but i

    Syntax: `{symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}`

    (def my-hashmap {:a "A" :b "B" :c "C" :d "D"})
    (def my-nested-hashmap {:a "A" :b "B" :c "C" :d "D" :q {:x "X" :y "Y" :z "Z"}})
    (def my-hashmap {:a "A" :b "B" :c "C" :d "D"})
    (def my-nested-hashmap {:a "A" :b "B" :c "C" :d "D" :q {:x "X" :y "Y" :z "Z"}})

    (let [{a :a d :d} my-hashmap]
    (println a d))
    ;; => A D
    (let [{a :a d :d} my-hashmap]
    (println a d))
    ;; => A D

    (let [{a :a b :b {x :x y :y} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y
    (let [{a :a, b :b, {x :x, y :y} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y

    Similar to vectors, if a key is not found in the map, the symbol will be bound to `nil`.

    (let [{a :a not-found :not-found b :b :as all} my-hashmap]
    (println a not-found b all))
    ;; => A nil B {:a "A" :b "B" :c "C" :d "D"}
    (let [{a :a, not-found :not-found, b :b} my-hashmap]
    (println a not-found b))
    ;; => A nil B

    You can provide an optional default value for these missing keys.
    You can provide an optional default value for these missing keys with the `:or` keyword and a map of default values.

    A
    (let [{a :a, not-found :not-found, b :b, :or {not-found ":)"}} my-hashmap]
    (println a not-found b))
    ;; => A :) B

    The `:as some-symbol` form is also available for hashmaps, but unlike vectors it can be specified anywhere (but still preferred to be the last two pairs).

    (let [{a :a, b :b, :as all} my-hashmap]
    (println a b all))
    ;; => A B {:a A :b B :c C :d D}

    And combining `:as` and `:or` keywords (again, `:as` preferred to be the last).

    (let [{a :a, b :b, not-found :not-found :or {not-found ":)"} :as all} my-hashmap]
    (println a b not-found all))
    ;; => A B :) {:a A :b B :c C :d D}

    There is no `& rest` for hashmaps.

    Shortcuts
    ---------

    Having to specify `{symbol :symbol}` is repetitive and verbose (it's almost always going to be the symbol equivalent of the keyword), so there are shortcuts available so you only have to type the symbol once.



    Keyword arguments for functions:
    --------------------------------


    Vectors + Hashmaps + Vectors...
    ===============================

    Here be dragons.

    * * *

    # Compojure
  23. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion destructuring.md
    Original file line number Diff line number Diff line change
    @@ -58,7 +58,9 @@ You can use both `& rest` and `:as some-symbol`.
    Function args usage:
    --------------------

    (defn foo [a b & [x y z]] ;; <= here we are using the `& rest` form, but at the same time we immediately destructure it
    With destructuring and the `& rest` form, you can specify optional arguments to functions.

    (defn foo [a b & [x y z]]
    (println a b x y z))
    (foo :a :b) ;; => :a :b nil nil nil
    (foo :a :b :x) ;; => :a :b :x nil nil
  24. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion destructuring.md
    Original file line number Diff line number Diff line change
    @@ -58,7 +58,7 @@ You can use both `& rest` and `:as some-symbol`.
    Function args usage:
    --------------------

    (defn foo [a b & [x y z]]
    (defn foo [a b & [x y z]] ;; <= here we are using the `& rest` form, but at the same time we immediately destructure it
    (println a b x y z))
    (foo :a :b) ;; => :a :b nil nil nil
    (foo :a :b :x) ;; => :a :b :x nil nil
  25. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion destructuring.md
    Original file line number Diff line number Diff line change
    @@ -23,7 +23,7 @@ You don't have to match the full vector.
    (println a b c))
    ;; => :a :b :c

    You can use `& rest` as the *last two items* to bind the remaining part of the vector to `rest`.
    You can use `& rest` to bind the remaining part of the vector to `rest`.

    (let [[a b & rest] my-vector]
    (println a b rest))
  26. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 33 additions and 9 deletions.
    42 changes: 33 additions & 9 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,8 @@
    Vectors
    =======

    Vector destructuring is the simplest form. It is similar to Python's list unpacking feature, but much more powerful.

    Syntax: `[symbol another-symbol] ["value" "another-value"]`


    @@ -15,25 +17,43 @@ Syntax: `[symbol another-symbol] ["value" "another-value"]`
    (println a d x y z))
    ;; => :a :d :x :y :z

    When a destructuring form "exceeds" a vector (i.e. there not enough items in the vector to bind to), `nil` will be binded to the excess symbols.
    You don't have to match the full vector.

    (let [[a b c] my-vector]
    (println a b c))
    ;; => :a :b :c

    You can use `& rest` as the *last two items* to bind the remaining part of the vector to `rest`.

    (let [[a b & rest] my-vector]
    (println a b rest))
    ;; => :a :b (:c :d)

    When a destructuring form "exceeds" a vector (i.e. there not enough items in the vector to bind to), the excess symbols will be bound to `nil`.

    (let [[a b c d e f g] my-vector]
    (println a b c d e f g))
    ;; => :a :b :c :d nil nil nil

    You can use `:as some-symbol` as the last two items in the destructuring form to bind the whole vector to `some-symbol`
    You can use `:as some-symbol` as the *last two items* in the destructuring form to bind the whole vector to `some-symbol`

    (let [[:as all] my-vector]
    (println all))
    ;; => [:a :b :c :d]

    (let [[a _ _ _ :as all] my-vector]
    (let [[a :as all] my-vector]
    (println a all))
    ;; => :a [:a :b :c :d]

    (let [[a _ _ _ [x y z :as nested] :as all] my-nested-vector]
    (println a all x y z nested))
    ;; => :a [:a :b :c :d [:x :y :z]] :x :y :z [:x :y :z]
    (println a x y z nested all))
    ;; => :a :x :y :z [:x :y :z] [:a :b :c :d [:x :y :z]]

    You can use both `& rest` and `:as some-symbol`.

    (let [[a b & rest :as all] my-vector]
    (println a b rest all))
    ;; => :a :b (:c :d) [:a :b :c :d]

    Function args usage:
    --------------------
    @@ -47,6 +67,8 @@ Function args usage:
    Hashmaps
    ========

    Hashmap destructuring is much more complicated, and can get quite verbose, but is much more powerful than vector destructuring.

    Syntax: `{symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}`

    (def my-hashmap {:a "A" :b "B" :c "C" :d "D"})
    @@ -60,13 +82,15 @@ Syntax: `{symbol :key, another-symbol :another-key} {:key "value" :another-key "
    (println a b x y))
    ;; => A B X Y

    (let [{a :a none :none b :b :as all} my-hashmap]
    (println a none b all))
    Similar to vectors, if a key is not found in the map, the symbol will be bound to `nil`.

    (let [{a :a not-found :not-found b :b :as all} my-hashmap]
    (println a not-found b all))
    ;; => A nil B {:a "A" :b "B" :c "C" :d "D"}

    You can provide an optional default value for these missing keys.

    Default values for when a key is not in the map
    ------------------------------------------------------
    A

    Shortcuts
    ---------
  27. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -15,6 +15,12 @@ Syntax: `[symbol another-symbol] ["value" "another-value"]`
    (println a d x y z))
    ;; => :a :d :x :y :z

    When a destructuring form "exceeds" a vector (i.e. there not enough items in the vector to bind to), `nil` will be binded to the excess symbols.

    (let [[a b c d e f g] my-vector]
    (println a b c d e f g))
    ;; => :a :b :c :d nil nil nil

    You can use `:as some-symbol` as the last two items in the destructuring form to bind the whole vector to `some-symbol`

    (let [[:as all] my-vector]
  28. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 15 additions and 0 deletions.
    15 changes: 15 additions & 0 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,7 @@ Vectors

    Syntax: `[symbol another-symbol] ["value" "another-value"]`


    (def my-vector [:a :b :c :d])
    (def my-nested-vector [:a :b :c :d [:x :y :z]])

    @@ -14,6 +15,12 @@ Syntax: `[symbol another-symbol] ["value" "another-value"]`
    (println a d x y z))
    ;; => :a :d :x :y :z

    You can use `:as some-symbol` as the last two items in the destructuring form to bind the whole vector to `some-symbol`

    (let [[:as all] my-vector]
    (println all))
    ;; => [:a :b :c :d]

    (let [[a _ _ _ :as all] my-vector]
    (println a all))
    ;; => :a [:a :b :c :d]
    @@ -22,6 +29,9 @@ Syntax: `[symbol another-symbol] ["value" "another-value"]`
    (println a all x y z nested))
    ;; => :a [:a :b :c :d [:x :y :z]] :x :y :z [:x :y :z]

    Function args usage:
    --------------------

    (defn foo [a b & [x y z]]
    (println a b x y z))
    (foo :a :b) ;; => :a :b nil nil nil
    @@ -44,6 +54,11 @@ Syntax: `{symbol :key, another-symbol :another-key} {:key "value" :another-key "
    (println a b x y))
    ;; => A B X Y

    (let [{a :a none :none b :b :as all} my-hashmap]
    (println a none b all))
    ;; => A nil B {:a "A" :b "B" :c "C" :d "D"}


    Default values for when a key is not in the map
    ------------------------------------------------------

  29. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 16 additions and 1 deletion.
    17 changes: 16 additions & 1 deletion destructuring.md
    Original file line number Diff line number Diff line change
    @@ -14,6 +14,19 @@ Syntax: `[symbol another-symbol] ["value" "another-value"]`
    (println a d x y z))
    ;; => :a :d :x :y :z

    (let [[a _ _ _ :as all] my-vector]
    (println a all))
    ;; => :a [:a :b :c :d]

    (let [[a _ _ _ [x y z :as nested] :as all] my-nested-vector]
    (println a all x y z nested))
    ;; => :a [:a :b :c :d [:x :y :z]] :x :y :z [:x :y :z]

    (defn foo [a b & [x y z]]
    (println a b x y z))
    (foo :a :b) ;; => :a :b nil nil nil
    (foo :a :b :x) ;; => :a :b :x nil nil
    (foo :a :b :x :y :z) ;; => :a :b :x :y :z

    Hashmaps
    ========
    @@ -27,7 +40,9 @@ Syntax: `{symbol :key, another-symbol :another-key} {:key "value" :another-key "
    (println a d))
    ;; => A D

    (let [{a :a b :b {}}])
    (let [{a :a b :b {x :x y :y} :q} my-nested-hashmap]
    (println a b x y))
    ;; => A B X Y

    Default values for when a key is not in the map
    ------------------------------------------------------
  30. @john2x john2x revised this gist Jul 26, 2014. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions destructuring.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    Vectors
    =======

    Syntax: `[symbol another-symbol] [target-value another-target-value]`
    Syntax: `[symbol another-symbol] ["value" "another-value"]`

    (def my-vector [:a :b :c :d])
    (def my-nested-vector [:a :b :c :d [:x :y :z]])
    @@ -18,7 +18,7 @@ Syntax: `[symbol another-symbol] [target-value another-target-value]`
    Hashmaps
    ========

    Syntax: `{symbol :target-key, another-symbol :another-target-key} {:target-key "target-value" :another-target-key "another-target-value"}`
    Syntax: `{symbol :key, another-symbol :another-key} {:key "value" :another-key "another-value"}`

    (def my-hashmap {:a "A" :b "B" :c "C" :d "D"})
    (def my-nested-hashmap {:a "A" :b "B" :c "C" :d "D" :q {:x "X" :y "Y" :z "Z"}})
    @@ -29,7 +29,7 @@ Syntax: `{symbol :target-key, another-symbol :another-target-key} {:target-key "

    (let [{a :a b :b {}}])

    Default values for when a key is not in the target map
    Default values for when a key is not in the map
    ------------------------------------------------------

    Shortcuts