yegor256
yegor256

Reputation: 105213

Consecutive calculations in Clojure

I'm trying to implement this logic in Clojure (just an example):

a = 1 + 5
b = a + 3
c = a + 4
d = c + a
return f(a, b, c, d) 

The best code I've managed to write so far looks like:

(let [a (+ 1 5) b (+ a 3) c (+ a 4) d (+ c a)] (f a b c d))

This looks rather cumbersome, mostly because in my real-life case these "add" operations are much more complicated and may take a few lines of code. I would rather prefer to write it like (Lisp style):

(set a (+ 1 5))
(set b (+ a 3))
(set c (+ a 4))
(set d (+ c a))
(f a b c d)

Is it possible in Clojure?

Upvotes: 0

Views: 140

Answers (3)

mokeefe
mokeefe

Reputation: 456

The set function in Clojure creates a set data type from another collection container as opposed to mutating the values of the variables. However, you could do the following:

(def a (+ 1 5))
(def b (+ a 3))
(def c (+ a 4))
(def d (+ c a))
(f a b c d)

The let statement allows you to do the same thing but not "pollute" your top-level namespace with the a, b , c, and d values. However, if you want to be able to hang on to and reference a, b, c, and d, a def would do the trick.

Upvotes: 2

Leonid Beschastny
Leonid Beschastny

Reputation: 51500

Actually, you almost found the best solution possible in Clojure:

(let [a (+ 1 5)
      b (+ a 3)
      c (+ a 4)
      d (+ c a)]
  (f a b c d))

You can't write Clojure code in imperative style, because it's a functional language. You can't freely use defs either, because all variables in Clojure are immutable. So, ones defined the can't be changed. So, if you want to temporary bind some variables, you should use let.

Upvotes: 4

jjpe
jjpe

Reputation: 684

No and that is by intent, as the (set ...) calls you're describing imply the use of mutable state in the way languages like Java and C# do. This is something Clojure actively avoids in order to manage state in a more sane way, something that really becomes important in concurrency. For more information I refer you to the Clojure website.

Furthermore, the let form is not cumbersome, it is a useful scoping tool: In your example a, b,c and d are all local to let. What this means is that once the instruction pointer steps out of the let, all of those bindings are forgotten.

In contrast, even if your (set...) example were to work, you would have polluted your namespace with all of these ephemeral names.

Upvotes: 4

Related Questions