[com.troy-west/wire "0.1.0-SNAPSHOT"]
A small Clojure library for explicitly wiring together functions into declarative computation graphs.
This approach has some similarities to Dataflow Programming. Unlike Dataflow Programming this library simply provides an approach to composing pure functions, it does not provide Dataflow variable or try to solve any concurrency related problem. By default it does not provide any memoization, caching, parrallel computation, partial evaluation or reactive programming.
This library was inspired from working with formula, either given in hand written form or via a spreadsheet. These can be tricky to work with for a number of reasons:
By making the workflow of the computations explicit with a declarative graph it helps handle many of these issues:
merge
and other simple
utility functionsFunctions can be declaratively wired together into a dependency map like such:
=> (def dep-map {:foo/c [[:foo/a :foo/b]
*]
:foo/d [[:foo/c]
inc]
:foo/e [[:foo/a :foo/c :foo/d]
+]})
The dependency map can be compiled to a graph as follows:
=> (require '[troy-west.wire :as wire])
=> (wire/compile-graph dep-map)
{:wire/dep-graph #clojure.tools.namespace.dependency.MapDependencyGraph
{:dependencies {:foo/c #{:foo/a :foo/b},
:foo/d #{:foo/c},
:foo/e #{:foo/a :foo/c :foo/d}},
:dependents {:foo/a #{:foo/c :foo/e},
:foo/b #{:foo/c},
:foo/c #{:foo/d :foo/e},
:foo/d #{:foo/e}}},
:wire/dep-map {:foo/c [[:foo/a :foo/b] nil],
:foo/d [[:foo/c] nil],
:foo/e [[:foo/a :foo/c :foo/d]
nil]}}
You can find out if there are any unbound variables within the graph using
free-variables
:
=> (def graph (wire/compile-graph dep-map))
=> (wire/free-variables (:wire/dep-graph graph))
#{:foo/b :foo/a}
To execute a computation using the graph you will need to provide values for the free variables:
=> (wire/execute-graph graph {:foo/a 15 :foo/b 3})
#:foo{:a 15, :b 3, :c 45, :d 46, :e 106}
You can also compile and execute in one step:
=> (wire/compile-and-execute dep-map {:foo/a 15 :foo/b 3})
#:foo{:a 15, :b 3, :c 45, :d 46, :e 106}
Bound values can be overwritten with values in the args
map,
useful for testing:
=> (wire/compile-and-execute dep-map {:foo/a 15 :foo/b 3 :foo/c 20})
#:foo{:a 15, :b 3, :c 20, :d 21, :e 56}
Dependency maps can be composed with merge
:
=> (wire/compile-and-execute (merge dep-map {:foo/b [[:foo/a] dec]})
{:foo/a 15})
#:foo{:a 15, :b 14, :c 210, :d 211, :e 436}
There are also a number of helper functions to add in composition of
dependency maps, see their doc strings for usage examples:
with-ns
, replace-keys
, replace-namespaces
, append-ns
, filter-ns
,
re-filter-ns
, list-namespaces
There are three built in functions for visualising graphs,
viz-graph-names
, viz-graph-results
and viz-graph-fns
.
Each can be called like:
=> (wire/viz-graph-names graph {:foo/a 15 :foo/b 3})
=> (wire/viz-graph-results graph {:foo/a 15 :foo/b 3})
=> (wire/viz-graph-fns graph {:foo/a 15 :foo/b 3})
Copyright © 2018 Troy-West, Pty Ltd.
Distributed under the Eclipse Public License either version 2.0 or (at your option) any later version.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close