Hacker News new | ask | show | jobs
by dreamdu5t 3773 days ago
Because there's functional as in only using pure functions (Haskell, ocaml) and functional as in access to higher order functions (JavaScript, erlang, clojure)
3 comments

> Because there's functional as in only using pure functions (Haskell, ocaml)

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.

I'd distinguish between (at least) three degrees of “purity”:

(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.

Pretty strange that you put Clojure in the "anything goes" category when it has been the clear leader when it comes to immutability. Lots of those languages you put in the other categories don't even have persistent data structures in their standard library.
Here is why: http://pastebin.com/t3Q3CW4j

This is particularly infuriating because the proper way to handle bound variables is already known: https://en.wikipedia.org/wiki/De_Bruijn_index .

No one is maintaining state by constantly clobbering namespace level variables in Clojure, though. What actually comes into play are ways the language and standard library encourages passing data around and manipulating it, which in Clojure is as immutable as you'll find in any language.
Clojure encourages me to program in the REPL, because there is no other way to know what is going on in such a semantically crazy language, other than trial and error.

And the state of the Clojure REPL is as mutable and imperative as it gets, as my paste showed.

Interestingly, Scala handles it http://pastebin.com/CT36K6Hj It feels like an artifact of the REPL tho, as one shouldn't be able to redefine x
Yep, statically typed languages tend to have no option but to handle this right. Otherwise, they risk unsoundness: Consider what would happen if you did `val x = "foo"` instead of `val x = 0`.

But there's still no type-level distinction between immutable and mutable bindings, which is why included Scala in the “anything goes” category.

> Absolutely anything goes. Examples: Racket (in the REPL), Lisp, Clojure, Scala, Erlang, etc.

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.

leaving runtime asides, which do you enjoy more Ocaml or Clojure?
To add to ohnomrbil's succinct reply, I absolutely enjoy being scolded by OCaml's compiler. The type inference is just marvelous and the code is almost as concise as Python etc. OTOH, the library ecosystem for OCaml is not even close to the stuff that's available for Clojure.
I use both, for different things. Clojure is more easily concurrent, and I love ClojureScript, so I tend to use it for web applications. OCaml is extremely useful for native code (I write a lot of personal productivity tools in OCaml).
> Because there's functional as in only using pure functions (Haskell, ocaml) and functional as in access to higher order functions (JavaScript, erlang, clojure)

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...

;-)

> Or functional as having proper closures.

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?

> Closures are an implementation detail.

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.

Arguing about terminology and the correct definitions/properties of functional languages only demonstrates the point - that the properties of a functional language are context-sensitive and subjective.
i thought ocaml ain't pure like that?
There are a couple of monadic IO systems for Ocaml - Lwt and Async which are pretty commonly used - and enable writing code using typed mutation/side effects.
You thought right. Ocaml is an impure functional language.