Here's an easy example. In some code I'm writing for my startup, I'm attempting to build the DAG that maximizes a scoring function. I permute through the candidates, and then run a scoring function. I perform greedy hill climbing , and return the DAG with the best score.
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.
Thanks for this. I didn't know about update-in. Are there other 'update' functions?
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.
Actually, when I said 'update', I meant the functions that in standard languages that would modify the existing structure return a new one, but it's great you found update-in. That's a beautiful function. There's also assoc-in, which is basically just a more specialized assoc-in.
I've built cyclical graphs in Clojure. The simplest form looks like
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.