#Clojure Doc Exploration
Go through them docs
** Last looked at "with-bindings"**
Agents are things. Part of writing async code in clojure
Refs are also things used within transactions (STM). Updated with functions like
alter
This function seems INCREDIBLY useful
(as-> (+ 1 2) sum
(+ sum 1)
(+ sum 2)) ; 6
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 are things created via atom
. These are essentially thread safe singletons mutated by functions like swap!
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
can be pretty handy for applying transducers
(into [] cat '((1 2) (3 4))) ; applies cat transducer to flatten a list
commute
is sort of like an atom's swap
, but commute
is for refs. Must be used within a transaction
This function is a really simple way to convert a predicate function into a java.lang.Comparator
cond
is very similar to case
. case
however uses "constant-time dispatch", the test expressions are not considered sequentially.
Another super useful function. Threads into the second position both for the test and value expressions.
(cond-> 1
(= 1) inc
(> 1) (* 42)) ; 84
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
This is how we start code in a transaction. You would alter any refs within the transaction using the alter
function
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
?
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"
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}