What about goto in clojure?

Yes, me too. I just prefaced my post, because there’s obviously going to be differences in opinion here, and it’s not like anyone can say one opinion is better than the other.

Ya, I agree. I think I just like to distinguish things more granularity as well as more generally.

For example, I think a def is imperative, in that it is a global write to memory, it isn’t a procedure or a function, but almost a pure instruction directly to memory or cpu.

A do I feel is more challenging. It can be used imperatively, for example:

(do
  (def a 20)
  (def b 30)
  (if (> a b)
    (def b "Hello World!")
    (def b "Bye bye World!"))
  (println b))

But I wasn’t free to use whatever I wanted inside the do, or in my opinion, it would have already started to become procedural. For example:

(do
  (let [a 20 b 30]
    (if (> a b)
      (println "Hello World!")
      (println "Bye bye World!"))))

This is now procedural code to me. I introduced local variables, and the idea of subroutines (the nesting of println inside if).

What do isn’t is functional. Or used functionally it is redundant and can be removed.

So I say, imperative is a series of instructions direct to cpu and memory. Even my use of if is pushing it in my opinion. Normally it would be a conditional jump to the instructions that defs b, but Clojure doesn’t have goto, so I had to cheat a bit.

Procedural is a set of instructions where instructions can be grouped inside of subroutines, aka, procedures, which can be nested in one another, and call each other, where execution automatically returns back to where we were and values can be passed in and out of them at known jump points. This adds the idea of scoped data, a move away from global data, and new instructions to manipulate that local data.

Functional makes away completly with global data, and with series of instructions. There are no instructions to cpu, or access to global memory. The entire program is a tree of functions composed together, which gets reduced using term re-writing into the final result:

(println (#(if (> a b) "Hello World!" "Bye bye world!") 20 30))

This is cheating as well, because println is an instruction, but since the computer only executes instructions, you need some somewhere to be useful, so normally in functional it is pushed to the edge like I did.

And where you contrast imperative and declarative. I think I don’t associate functional with declarative per say. It isn’t imperative for sure. But declarative to me is more orthogonal. Imperative is when you say “How to do something, but not what”. And declarative is when you say “What to do, but not how”, and the computer figures out how automatically. For example, html is like that, or Apache Ant, yet those are not functional languages, but they are declarative. Logic programming is another example. You could say ML is declarative as well. Sometimes, FP is said to be more declarative, but that’s more to do with the available libraries and features common to FP langs then FP itself I feel. Like higher level functions, like filter, remove, partition, etc., are closer to What then How. But you could have an FP lang without them. Or monadic let is more declarative in that you say What, and the computer figures out how to order the things for it to work. But you can have an FP lang without monadic let.

Edit: Oh, and I had kind of lost my train of thought. So above is my granular differentiation. In practice, borders are blurred. That’s when I switch to a more general taxonomy. The essence of Clojure is functional. It tries to be as much as is practical. So in that way, it isn’t an imperative or procedural language. Just like a SUV isn’t a truck, even though I can use it to move a TV around, or I can attach a UHAUL to it. That’s because the essence of an SUV is different to that of a truck. Yet, it is still a car, with an above average cargo size, and a potentially more powerful motor, which could have higher clearance, etc.

Anyways, that’s just how I like to model these.

3 Likes