Skip to content

Instantly share code, notes, and snippets.

@brianium
Last active December 19, 2016 17:20
Show Gist options
  • Save brianium/3a3e42b95d1c2bc2adfd0ba0e9500a84 to your computer and use it in GitHub Desktop.
Save brianium/3a3e42b95d1c2bc2adfd0ba0e9500a84 to your computer and use it in GitHub Desktop.

#Clojure Doc Exploration

Go through them docs

** Last looked at "with-bindings"**

agent

Agents are things. Part of writing async code in clojure

refs

Refs are also things used within transactions (STM). Updated with functions like alter

as->

This function seems INCREDIBLY useful

(as-> (+ 1 2) sum
  (+ sum 1)
  (+ sum 2)) ; 6

transients

Transients are controlled local mutable values meant to increase performance. You should return them as persistent via persistent!. Immutable accessors and mutators like assoc or conj have transient equivalents of assoc! and conj!

atoms

Atoms are things created via atom. These are essentially thread safe singletons mutated by functions like swap!

bean

This function seems useful for certain Java constructs. Seems like a cool way to treat a Date JavaBean like a plain hash-map:

(import java.util.Date)
(def ^:dynamic *now* (Date.))
(get (bean *now*) :day) ;3

into

into can be pretty handy for applying transducers

(into [] cat '((1 2) (3 4))) ; applies cat transducer to flatten a list

commute

commute is sort of like an atom's swap, but commute is for refs. Must be used within a transaction

comparator

This function is a really simple way to convert a predicate function into a java.lang.Comparator

cond

cond is very similar to case. case however uses "constant-time dispatch", the test expressions are not considered sequentially.

cond->

Another super useful function. Threads into the second position both for the test and value expressions.

(cond-> 1
        (= 1)  inc
        (> 1) (* 42)) ; 84

condp

Like cond but accepts a binary predicate with the expression

(condp = 1
    1 "one"
    2 "two"
    :default "nah") 

##delay Creates a "delay" that is forced when it is asked for via @ dereffing or the force function. Subsequent calls will be cached

(def thang (delay (+ 1 1)))
; @thang => 2
' thang => #delay[{:status :ready, val 2}] ; val is nil before dereffing

dosync

This is how we start code in a transaction. You would alter any refs within the transaction using the alter function

dotimes

Runs something n number of times. Bindings are name => n, and the name will be bound with a value between 0 and n -1

(dotimes [lol 5]
    (inc lol)
    (println lol))
; 0
; 1
; 2
; 3
; 4

##eduction eduction seems like a pretty core way to apply a transform to a collection via transducers

(eduction (map inc) (range 5))

##eval eval is a lot cooler than most other languages. It evaluates a data structure representing a form.

(eval "(println [1 2 3])") ; just returns the string, nothing eval'ed
(eval (read-string "(println [1 2 3])")) ; prints [1 2 3]

##every-pred Seems cool for composing a bunch of functions and running against a variable set of arguments. Not 100% on the use over every? which accepts a predicate and a collection. Maybe every-pred is more composable? Maybe has a broader function using apply?

Note

Functions like every? and any? have built in complements like not-any? and not-every?

##ex-info Seems like a good way to build an exception that carries extra data. Paired with ex-data, you could make and consume some useful error messages.

(def e (ex-info "ERROR", {:status "lolz"}))
(ex-data e) ; => {:status "lolz"}

##extend ZOUNDS!!! This is extremely powerful. You can extend a type with a protocol. That counts for existing types and interfaces too. Just patch an existing type with new behavior.

(defprotocol Lolz
  "A simple lolz"
  (lol [this] "Make me lol"))
  
(extend java.util.StringTokenizer
  Lolz
  {:lol (fn [this] (println "lolol"))})
  
(def s (java.util.StringTokenizer. "lol string"))

(lol s) ; => lolol

extend-type looks like a little suger for defining implementations inline.

(extend-type java.util.StringTokenizer
        Lolz
        (lol [t] (println "lolol")))

##extenders This just keeps getting cooler. extenders will actually return a collection of of the types that are extending a given protocol.

(extenders Lolz) ; => (java.util.StringTokenizer)

##find find returns an entire map entry, not just the value (as is the case with get))

(find {:one "one" :two "two" :three "three"}, :two) ; => [:two "two"]

##fnil fnil can create a function that replaces nil arguments with defaults

(defn say-hello [name] (str "Hello " name))
(def say-hello-with-defaults (fnil say-hello "World"))

(say-hello "Brian") ; => "Hello Brian"
(say-hello-with-defaults nil) ; => "Hello World"

##for List comprehension. You can return a lazy collection evaluating the given expressions

(for [x [0 1 2 3 4 5]
      :let [y (* x 3)]
      :when (even? y)]
  y)

##future future and future-call seem like quick ways to do some stuff on another thread and return the result as promise

(def p (future (+ 1 2)))

@p ; => 3

##gen-class A clojure way to create a Java class. This is unimplemented in clojurescript. This may have uses if leveraging a particular Java library that expects an implementation to extend a base class?

##group-by Functions like group-by and frequencies seem useful for getting stats on a particular collection.

(group-by count ["a" "as" "asd" "aa" "asdf" "qwer"])
; => {1 ["a"], 2 ["as" "aa"], 3 ["asd"], 4 ["asdf" "qwer"]}

(frequencies [1 1 2 2 3 3 3 3])
; => {1 2, 2 2, 3 4}

##if-some different than if-let as it will pass the test if it evaluates to anything other than nil. So false will pass the if-some test

(if-some [a 10]    :true :false)   ; => :true
(if-some [a true]  :true :false)   ; => :true
(if-some [a false] :true :false)   ; => :true
(if-some [a nil]   :true :false)   ; => :false

;; for comparison
(if-let [a 10]     :true :false)   ; => :true
(if-let [a true]   :true :false)   ; => :true 
(if-let [a false]  :true :false)   ; => :false
(if-let [a nil]    :true :false)   ; => :false

##io! io! seems like something you would call to ensure your function is never used within a transaction.

(defn scary-for-multiple-threads []
  (io! (println "scary io!")))

##iterate Returns a lazy sequence of values based on a function being applied to an argument x. Really easy to create infinite loops here..... So it works better with functions like skip and take. "better" meaning better for me not locking up my repl.

(iterate inc 1); => keeps going...and going...and going.....
(take 5 (iterate inc 1)); => (1 2 3 4 5)

##juxt juxt is a pretty interesting concept. Take a bunch of functions and return a single function that returns a vector of results for each of those functions.

(def bunch-o-math (juxt + - *))
(bunch-o-math 2 3); => [5 -1 6]

##keep Another useful function for applying a function to a collection and weeding out nil values that result from the function being applied. Result is lazy. keep-indexed is a related function, but the function argument is also given the index - i.e (f index item)

(keep seq [[1 2] [] [1 2 3]]) ; => ((1 2) (1 2 3))

##key This function taught me that a map entry is not just [:one 1], but it is an actual type.

(key [:one 1]); => EXCEPTIONS EVERYWHERE
(def e (find {:one 1} :one))
(key e); => :one

##keyword Create a keyword with an optional namespace. I am starting to see some inconsistencies when a function calls for a namespace. Do you use 'ns or do you use "ns"? Maybe the same thing for names?

(keyword "user" "lol"); => :user/lol

##letfn define functions in a lexical context. functions defined this way do have access to one another

(letfn [(twice [x]
                (* x 2))]
        (twice 4))

##load-string This is like the evil eval from other languages. There is a family of these things like load-file and load-reader

##locking A macro to synchronize things

(def o (Object.))
(future (locking o
                (Thread/sleep 5000)
                (println "done1")))

##mapcat The function supplied to mapcat should return a collection

##mapv mapv differs from map only in that it returns a vector - this means the collection is NOT lazy

##max-key Seems generally useful. Returns the largest x for f(x) (map-key f x y z) - has a similarly named min-key

(max-key count "abc" "abcd" "abcde"); => "abcde"

merge-with

This function merges maps and resolves key conflicts by applying a function - good if you don't want to simply overrwrite a repeated key.

(merge-with + 
            {:a 1  :b 2}
            {:a 9  :b 98 :c 0})
 ;;=> {:c 0, :a 10, :b 100}

##ns-* functions of the form ns-* give information about the given namespace. What mappings exist in the namespace, what interns, etc...

##partition Return a lazy sequence of a collection broken into partitions.

(partition 2 [1 2 3 4 5 6])
;; => ((1 2) (3 4) (5 6))

;; providing a step
(partition 2 1 [1 2 3 4 5 6])
;; => ((1 2) (2 3) (3 4) (4 5) (5 6))

partition-all is similar, but it will include incomplete partitions. partition would chop [1 2 3 4 5] into ((1 2) (3 4)) and partition-all would chop it into ((1 2) (3 4) (5))

partition-by accepts a function and a collection, and returns a new partition every time the function would return a new value (does not alter the value)

##pcalls executes a bunch of no arg functions in parallel and returns a lazy sequence of their values.

(pcalls (fn [] [1 2 3]) (fn [] [4 5 6]))
;; => ([1 2 3] [4 5 6])

##peek Same as first for a list or queue. Same as last BUT more efficient than last for a vector

##persistent! returns a persistent version of the transient collection. makes future use of the transient impossible (exception is thrown)

(persistent! (transient []))
;; => []

##pmap like map but parallel!

Interestingly

Semi-lazy in that the parallel computation stays ahead of the consumption, but doesn't realize the entire result unless required. Only useful for computationally intensive functions where the time of f dominates the coordination overhead.

##pop Learning that these sort of access functions operate in the most efficient way for the given collection. For instance pop will return a new list with the first item missing. However it will return a new vector with the last element missing.

(pop '(1 2 3))
; => (2 3)

(pop [1 2 3])
; => [1 2]

##prefer-method causes a multimethod to prefer a dispatch value match over another

##pvalues return a lazy sequence of values from parallel executed expressions

(pvalues (expensive-calc-1) (expensive-calc-2))
; => (2330 122)

Of interesting note from the clojure docs page:

pvalues is implemented using Clojure futures. See examples for 'future' for discussion of an undesirable 1-minute wait that can occur before your standalone Clojure program exits if you do not use shutdown-agents.

##quote I need to learn more about this in general, the different variets, the values, etc.... This seems like a good resource

##reader-conditional What is a reader conditional?

##reduced Wraps a value in such a way that a call to reduce will terminate with the value. Seems like the way to bail out of a call to reduce when a certain condition is met

##reductions Returns a sequence of intermediary values of a reduction. Seems like a really cool way to see the path a reduction takes

(reductions + [1 2 3 4])
; => (1 3 6 10)

##reify As far as I can tell, this is a way to make dynamic instances of a protocol/interface

An example is given on clojure docs of reifying a protocol composed of another record implementing a protocol with the intention of overriding that method. Like a Grape record having a subtotal function, but a coupon function that reifys a fruit with a subtotal function that delegats to the composed grape record but takes 25% off the result of the grape subtotal call. (Hope this mess of text makes sense later)

##replace Probably one of the most confusing functions i have seen so far. Basically selects when using a vector smap (first arg) and replaces when using a map

(replace [:zero :one :two :three] [0 2])
; => [:zero :two]

(replace {2 :a, 4 :b} [0 1 2 3 4 5 6])
; => [0 1 :a 3 :b 5 6]

##reversible? Check if the collection is reversible. Of note, vectors are reversible, but lists are not.

##rseq Constant time so faster than reverse. ONLY works on vectors and sorted maps

##rsubseq rsubseq and subseq have some interesting rules when applying the "long" form with regards to test conditions and keys

##run! Calls a function for side effects on every item in a collection

(run! println [1 2 3 4])
; => 1
; => 2
; => 3
; => 4

##sequence Coerce a collection into a sequence. (sequence []) returns () instead of null - as opposed to seq. Does not force a lazy sequence, and it seems like a cool way to apply a transducer to a collection as well.

(sequence (map inc) [1 2 3 4])
; => (2 3 4 5)

##some (some pred coll)

Does not just return a boolean. Returns the first truthy value for predicate. A common use case is to use a set as the function when searching for the first key

(some #{:fred} coll)

##some-> and some->> The availability of various "threading" functions should be remembered. Threading seems like a core concept in clojure via some-> -> as-> cond-> and the like

(some-> []
  (seq)) ;=> nil
  
(some-> [1]
  (seq)) ;=> (1)

##some-fn Compose a function that passes true if ANY of the composed functions returns true

((some-fn even? pos?) -4 -3 -2 -1) ;=> false
((some-fn even? pos?) 1 3) ;=> true

#spit and slurp These functions are core functions for reading and writing to files. A lot simpler than creating a bunch of Java objects

##split-with Split a collection with a predicate. Doesn't split until it finds a value that meets the condition - does not consider complements.

(split-with pos? [-1 -2 -3 0 1 2 3])
; => [() (-1 -2 -3 0 1 2 3)]

I sort of expected the above to split the collection into 2 collections - one containing negatives, and one containing positives. However, pos? did not return true until after the negatives had been passed over.

(split-with neg? [-1 -2 -3 0 1 2 3])
; => [(-1 -2 -3) (0 1 2 3)]

This does work, because neg? returns true up to a point

##subs A standard substring function (subs "hello" 1). Clojure does have things people use!

##sync Like dosync but allows extra options. Extra options are not supported however, and have not been for over 6 years now. Just use dosync

#take and friends take, take-last, take-nth, take-while are ways to grab things out of collections! huzzah! produce transducers and are really nice when working with lazy collections - suffers from similar complement issues as split-with. Maybe "suffers" is the wrong word, it's probably correct and I just don't know what a computer is.

##test If a function defines :test meta, this function will actually run that test! Seems pretty cool, but I wonder if people actually use this in large code bases.

(defn my-function
        "this function adds two numbers"
        {:test #(do
                  (assert (= (my-function 2 3) 5))
                  (assert (= (my-function 4 4) 8)))}
        ([x y] (+ x y)))
        
(test #'my-function)

##time seems like a dead simple way to get some metrics on an expression

(time (+ 1 1))
(time (map inc [1 2 3 4 5]))
(time (pmap inc [1 2 3 4 5]))

##trampoline Use this for doing mutual recursion . Rad Guide Here

##transduce This is like reduce with a transducer.

(transduce (map inc) + [1 2 3 4 5])
; => 20
(reduce + [1 2 3 4 5])
; => 15

##transient convert a persistent collection to a transient collection in CONSTANT TIME. The purpose of these is local mutability for performance sake. Clojure throws exceptions if you call persistent functions on them - i.e assoc instead of assoc!

(defn vrange [n]
  (loop [i 0 v []]
    (if (< i n)
      (recur (inc i) (conj v i))
      v)))

(defn vrange2 [n]
  (loop [i 0 v (transient [])]
    (if (< i n)
      (recur (inc i) (conj! v i))
      (persistent! v))))

;; benchmarked (Java 1.8, Clojure 1.7)
(def v (vrange 1000000))    ;; 73.7 ms
(def v2 (vrange2 1000000))  ;; 19.7 ms

##var and var-get Handy for returning Var objects and getting the values out of them. I feel ike there may be some cool things you can do with this. Reflection type things? I have no idea what I'm doing.

(def m {:one 1 :two 2 :three 3})
(var m)
; => #'user/m
#'m
; => #'user/m
(var-get #'m)
; => {:one 1 :two 2 :three 3}
(var-get (var m))
; => {:one 1 :two 2 :three 3}

##var? See that a thing is an actual Var object.

(var? m) ;=> false
(var? (var m)) ;=> true

##vec Converts a collection to a vector. Calling vec on a map returns a vector of real deal map entries that will pass the map-entry? test.

##vector Creates a vector out of variadic arguments. These variadic functions seem super ripe for apply type uses.

(apply vector '(1 2 3 4))
; => [1 2 3 4]

##volatile! Labeled as faster atoms, but they give up atomicity so they should only be used with thread isolation.

##when and friends when, when-first, when-let, when-not, when-some - elegant ways to do something if a test passes. The let, first, and some varieties support bindings of the things that pass conditions. super handy!

##while

(while (pos? @a) (do (println @a) (swap! a dec))) ; counts down from 10 until nil

##with-bindings Maps values to vars for thread local bindings

(def ^:dynamic x 1)
(with-bindings {#'x 2} x)
; => 2

##with-in-str Binds values to in against a fresh StringReader - seems like a really cool way to test values relying on STDIN - things that use read-line

##with-open Awesome way to handle resources. Calls .close on all bindings created. Guarantees that opened files/resources are closed when used in this way

##zipmap Create a map containing keys and values zipped together. Seems like a pretty foundational way of creating maps?

(zipmap [:a :b :c :d] [1 2 3 4])
; => {:a 1, :b 2, :c 3, d: 4}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment