3 ms·
Clojure has more than a handful of data-types which allow you to mutate/change values. You have 'ref' which allows for multiple observers and manipulators that
by lbj 8y ago
Clojure has more than a handful of data-types which allow you to mutate/change values. You have 'ref' which allows for multiple observers and manipulators that all see a discrete timeline. Think of a bank-transaction where two withdrawals run in parallel would yield a negative balance. Refs prevents that. Refs are mostly for synchronicity.
There's also atoms and agents to look at, but the overall perspective is that the world is as the world is and those who observe it always do so with some delay. The discrete timemodels allow you to have consistent views of the world from multiple observers.
This is a the heart of Datomics data-model. Nothing ever changes. If you commit a fact like "fred likes pizza" at 2pm. Fred will always be known to have liked pizza at 2pm. If you later commit that Fred likes apples. That will only be true from the point in time in which you commit, but you'll still be able to see that fred used to like pizza.
The IO is a side-note, but living on the JVM Clojure has native access to everything from files to streams and you can interact with them just like Java people do. There's a few helpers like with-io to manage multiple simultaneous writes, but they're rarely used.
Haskell in this regard, has the IO Monad which is briefly commented on the article. Its sort of a trick and as I understand it Haskell has no ambition of being the go-to concurrency language. It has recently had something like Refs/STM added though, haven't looked into it much.
- atombender 8y agoThanks for the explanation. Sounds like Clojure allows mutation and side effects all over the place, but that it has some nice libraries for handling immutability and sequencing in various ways so that you can write consistent programs. That sounds nice, but also not particularly unique or interesting. The IO monad in Haskell is no trick, but I can understand why you would think that.
- lbj 8y agoNo I'm sorry, I didn't explain it correctly then. I was commenting specifically on the data-types which can be mutated but only in a thread-safe/concurrent-safe manner. Everything else, incl the entirety of the core language, is immutable and functional. You have to go out of your way to mutate. Its a functional Lisp tightly integrated with the JVM and compiles to both Java bytecode and Javascript. I think that makes it unique.
- atombender 8y agoSo immutable, but side-effectful. As far as I can see, there's no effects system for I/O. For example, a function like print doesn't seem to return anything, if I understand the documentation correctly (which isn't easy, because it (e.g. [1]) seems to completely lack signatures, so the only way to tell is to look at the code!). For example, it seems that to print an array of lines to stdout, you use something like doseq, which is like a "for each" function that is side-effectful. This is how OCaml works, too. [1] https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/print https://clojure.github.io/clojure/clojure.core-api.html#cloj...
- lbj 8y agoAlmost correct. The signature is there, eg. > Usage: (print & more) '& more' means 'any number of arguments stuffed into a sequence called more' > (print [1 2 3]) "[1 2 3]" nil There are a number of ways to print an array of lines and doseq is one. Its designed for statements at have no return.
- atombender 8y agoI saw that, but the signature has no types or no indication as to what the return value might be. If you look at the documentation for functions that do have return values, there's no signature either, just a fairly vague English description of what it returns. Dynamic duck-typing all the way, no type inference. Anyway, my point was, no effects system. There's no way to determine if something has side effects or prevent them. Very far from Haskell's purity. I wouldn't criticize Haskell for a "trick" that enables the impressive feat of maintaing purity with side effects (while at the same time maintaining strict enforcement of types throughout) when Clojure doesn't even have any kind of effects management.