This is not true. Having written a good amount of OCaml I would argue that programming with side-effects in OCaml is extremely approachable - almost as much as Clojure. There are mutable data structures in the stdlib (Array, Hashtbl) and IO etc. is straightforward. Like Clojure, there exists a ref type which can be easily mutated. It's one of the reasons why OCaml strikes as an extremely pragmatic language to me.
(0) Absolutely anything goes. Examples: Racket (in the REPL), Lisp, Clojure, Scala, Erlang, etc.
(1) Values are immutable, but any computation might have any effect. Examples: Standard ML, OCaml (mostly), Racket (mostly).
(2) Values are immutable, and computations are type-annotated with their possible effects. Examples: Haskell, Idris, Ur/Web.
This is particularly infuriating because the proper way to handle bound variables is already known: https://en.wikipedia.org/wiki/De_Bruijn_index .
And the state of the Clojure REPL is as mutable and imperative as it gets, as my paste showed.
No, you can't: http://pastebin.com/SdbKM7V7
In ML and Haskell, a new variable might shadow an old one (if they have the same name), but they are still different variables.
Shadowing is slightly harder to implement than rebinding, but it provides a useful guarantee for the user: the meaning of existing definitions remains stable even if new definitions are introduced into the environment.
I'm inclined to think the Clojure REPL is more conducive to flailing around. Now, this might sound like derision, but it isn't intended that way: Flailing around can be a very time-efficient way to familiarize oneself with an unknown domain, especially if the cost of making wrong design decisions is small.
But at some point one has to consolidate what one already has, and, in my experience, Clojure makes this very difficult.
> I guess one programmer's sandbox is another programmer's hellish nightmare of mutability.
If you absolutely want mutable definitions, you can have them in Haskell (with some noise) and ML (with no noise) too: http://pastebin.com/00ScnFxC . So a Haskell or ML programmer always has at their disposal whatever they think is the best tool for the job.
Can I have it the other way around in Clojure?
Haha, yes. This is how I feel about Matlab, actually. But I suppose Clojure is no different in this respect.
I much prefer the Haskell approach: make dangerous things hard to do. Unfortunately, a majority of programmers consider that to be "unpractical".
But there's still no type-level distinction between immutable and mutable bindings, which is why included Scala in the “anything goes” category.
Well you can't mutate variables and data in Erlang. (Try X=1,X=2 in a repl, it will fail). There is a thing called process dictionary but it is frowned upon. Concurency is handled by processes. But that's a different thing.
Or functional as having proper closures.
Or tail call elimination.
Or using immutable data, or immutable variables.
Or minimizing mutable state.
Or being decalrative.
etc...
;-)
Closures are an implementation detail.
> Or tail cail elimination.
Tail call elimination is just the right way to implement tail calls in a strict language.
> Or using immutable data, or immutable variables.
Variables don't “mutate”, they are substituted with other expressions. What imperative languages have is “assignables”.
> Or minimizing mutable state.
Functional programs have plenty of state - which changes over time. You can't have computation without traversing a state space - over time.
> Or being declarative.
What (technical!) definition “declarative” are you using?
Except when they are not there done properly (cough cough Python), it not so fun doing functional programming.
> Tail call elimination is just the right way to implement tail calls in a strict language.
Well Erlang is not strict and has tail call elimination. Because of lack immutability, recursion is used. Without tail call elimination recursion will blow the stack.
> Variables don't “mutate”, they are substituted with other expressions. What imperative languages have is “assignables”.
Yes they do. X=X+1 -- Variable mutated. Like it or not that is the bread and butter of programming. Unless someone did strictly functional programming and math. Then I can see how they'd be very confused by that statement.
There is also immutable vs mutable data. For example both Erlang and Elixir have immutable data. But Elixir has mutable variable, while Erlang doesn't.
As for assignables, I've never heard that word. I went to the standard 4 year CS program. Seemingly did a regular curriculum. Is that a translation from another langauge or a functional programming terminology?
> Functional programs have plenty of state - which changes over time.
Some have more, some less. Minimizing means making it explicit, passing it around, using immutable data. As opposed to say sticking it in a large object instance in a global singleton and then everything calls 100 something methods to mutate it.
> What (technical!) definition “declarative” are you using?
The point I think is, it is just as technical as "functional" is. It has a bit of a "No True Scotsman" thing going for it.
But as a heuristic think maybe about when you'd use patern matching to destructure something vs say a nested set of if and elses.