"Drinking through a fire hose", "understanding corner cases", and such are just euphemisms. Where's the beef?
"Drinking through a fire hose", "understanding corner cases", and such are just euphemisms. Where's the beef?
Since this is Clojure, and my DAG is build from Clojure's persistent data structures, iterating through all possible dags is easy. Clojure's "update" functions return new structs that share structure with the original, both the original structure and the new one exist at the same time. If I were using mutable data structures, I'd either have to deep copy a new DAG (slower), or write "rollback" code (buggy).
Additionally, because the Clojure data structures are purely functional, and Clojure includes tools for multi-threaded synchronization, parallelizing this algorithm is trivial.
A separate example: I have an existing function that can take several minutes to an hour to run. I wanted to add a button to the web UI that says "go run the function". Of course, you don't want multiple versions running at the same time, so you need to queue up the function call, and you don't want the user to queue up 5 calls when they only need 1. It took all of about 4 lines of clojure to make the function run in a separate thread and handle all of the above issues, and I'm guaranteed to never have multithreading bugs in that code.
In summary
* purely functional data structures greatly simply multi-threaded programming, and make some algorithms easier to write.
* Clojure is designed from the ground up to make multi-threading easy and painless. Many multi-threading tools are built into the language, and you don't have to deal with locking and deadlock unless you drop into the Java synchronization primitives.
However, it's a good thing you want a DAG, because with immutable data structures you're hosed if you want a cyclic graph. Or at least you won't be building them out of such structures, which means you aren't getting to use Clojure's functions for sequences, collections and maps. Thus Clojure does not seem to be a good tool for graphs.
I've built cyclical graphs in Clojure. The simplest form looks like
{:nodes #{:a :b :c}
:edges {:a #{:b}
:b #{:c}
:c #{:a}}}
(for non-clojurians, {} is a map, and #{} is a set)The biggest advantage for my coding has actually been in my day-to-day Python work, where I'm much improved at designing functionally, parallelizing with multiprocessing, and building decorators and context functions to remove boilerplate code. So my Python is faster and cleaner; this is all thanks to being able to to think better about code design after working in Clojure.
For a good example of "why Clojure" take a look at Cascalog:
https://www.assembla.com/wiki/show/d9Z8_q-Omr35zteJe5cbLr
which leverages Hadoop/Cascading Java libraries and combines them with a Lisp-style custom query language.
http://www.paulgraham.com/avg.html
You'll want to not just read a book, but also get hands on experience with the language. That's where I found Clojure a good choice for me since I could work on problems of interest to my work and reuse existing Java libraries.
Joy of Clojure also presents a persuasive argument in the opening chapter for Clojure, Lisp and functional programming. There is a pdf of that chapter available for free from the author's website:
Clojure really shines in complex concurrent applications. In our case, it's a search engine for e-commerce, offered as SaaS, with instant search (so speed really matters). Without Clojure it would have been much more difficult to manage problems like concurrent switching to a new index while queries are being serviced.
I was initially skeptical and worried about implementation quality, but over 1.5 years of development we found exactly ZERO bugs in the language itself.
So there is beef. Start using Clojure and you'll find it.