If you put a clojure.lang.IDeRef
instance like a deferred value (created by defer
) or future into the map, deref
will be automatically called when you access it. This way, the map can be thought of as a lazy map.
(def m (fun-map {:a (future (+ 5 3))}))
(:a m) ;=> 8
Tip
|
You can specify :keep-ref to disable this default feature, and use fnk to force it to be lazy for individual values.
|
Your values can now depend on the map itself, most commonly on other values.
(def m
(fun-map {:numbers (range 10)
:cnt (fnk [numbers] (count numbers))
:sum (fnk [numbers] (apply + numbers))
:average (fnk [cnt sum] (/ sum cnt))}))
This feature is similar to Plumatic Plumbing’s graph, it even has the same name fnk
macro! The difference is that fun-map is a normal map, you could update the values (and the fnk
function) at any time. You could use a plain map if you want to test some complex computations.
A fun-map can track the realization order of its values by specifying a :trace-fn
option, combine this and the dependency injection nature, leads to a simple lifecycle management feature.
life-cycle-map
is a fun-map that can orderly close your lifecycle components.
(def system
(life-cycle-map
{:component/a
(fnk []
(closeable 100 #(println "halt :a"))) ;;(1)
:component/b
(fnk [:component/a]
(closeable (inc a) #(println "halt :b")))}))
(touch system) ;;(2)
(halt! system) ;;(3)
-
closeable
function turns a value to a closeable value, the specified close function will be called when the whole system is beingclose
. -
touch
travels the system, and makes potential lazy values realized, in a real application, you may not want to do it. -
halt!
is a function that closes a closeable value.
Waterfall library uses life-cycle-map
to do dependency injection and lifecycle management, turns Kafka usage into map accessing.
The complete API documents are on cljdocs.
Some of the most frequently used APIs are:
-
fun-map
-
fnk
(macro) -
fw
(macro)
(defn book-of
[connection author]
(-> (fun-map {:datomic/db (fnk [:datomic/connection] (d/db connection)) ;;(1)
:books (fnk [:datomic/db author]
(d/q '[:find ?e
:in $ ?name
:where [?e :book/author ?name]]
db author))
:book-count (fnk [books] (count books))})
(assoc :datomic/connection connection :author author))) ;;(2)
(book-system (d/connect "datomic:mem://books") "Harry Potter")
-
fnk
accepts namespaced keywords. -
by
assoc
key-value pairs to a fun-map, you turn Datomic API into a map.
Fun-map using kaocha as the test runner.
-
use
clj -M:test --watch
to automatically run tests whenever code changes.