14
(defn make-adder [x]
  (let [y x]
    (fn [z] (+ y z))))
(def add2 (make-adder 2))
(add2 4)
-> 6

I am trying to figure out this let example in clojure. What is the y variable it never seems to be set to anything. I do not understand the let syntax.

eat_a_lemon
  • 3,158
  • 11
  • 34
  • 50
  • It's binding `y` to `x`. – Barmar Mar 05 '14 at 17:12
  • 1
    ah duh thanks makes sense now – eat_a_lemon Mar 05 '14 at 17:16
  • 3
    A pedantic point, y is not a variable for its value cannot ever vary. There are `vars` in Clojure, but they are rarely used in let bindings (`defn` here creates a var named `make-adder`, and it and `add2` are the only variables shown here). – noisesmith Mar 05 '14 at 17:20
  • This code example is actually from https://clojure.org/about/functional_programming; last code snippet under "First-class functions" – alichaudry Feb 17 '17 at 04:11

3 Answers3

19
(let [y x]
    <body>)

evaluates <body> in a lexical context where y is bound to the value of x.

See the Clojure documentation for the description of let syntax. The general form is:

(let [sym1 val1
      sym2 val2
      sym3 val3
      ... ]
    <body>)

Each symN is bound to the corresponding valN.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    A nitpick: your naming here is misleading, unless a valN is of type var, no varN is a var. – noisesmith Mar 05 '14 at 17:23
  • 1
    Thanks, that's a difference between Lisp and Clojure I wasn't aware of. I've updated my answer to use `symN` instead. – Barmar Mar 05 '14 at 17:33
11

This function:

(defn make-adder [x]
  (let [y x]
    (fn [z] (+ y z))))

Itself returns a first-class function (a function that can be returned, passed around and assigned to a name just like any other value). Inside the let, x is bound to y, and so the function above is equivalent to this function below:

(defn make-adder [x]
  (fn [z] (+ x z)))

So that when make-adder is called with the value 2, it returns this first-class function:

(fn [z] (+ 2 z))

Remember, a first-class function can be assigned to a name, as in this line:

(def add2 (made-adder 2))

The line above is therefore equivalent to this code:

(def add2 (fn [z] (+ 2 z)))

And so is equivalent to this code also:

(defn add2 [z] (+ 2 z))

Which means that when add2 is called:

(add2 4)

The expression above evaluates to this:

(+ 2 4)

Which evaluates to 6.

djhaskin987
  • 9,741
  • 4
  • 50
  • 86
  • 1
    Nice, detailed answer, but 90% of it has nothing to do with his question, which was just about `y`. – Barmar Mar 05 '14 at 17:35
  • True. I wanted to fully explain the example. – djhaskin987 Mar 05 '14 at 17:46
  • +1 Thank you for the answer. I came to SO because the documentation wasn't doing it for me, and although the `let` explanation was lacking here, this is a very good explanation of the non-`let` stuff in the code snippet in the question. – alichaudry Feb 17 '17 at 04:10
1

Let expression is standard in many functional programming languages. What is the "let" keyword in functional languages like F# and OCaml for?

Community
  • 1
  • 1
aarti
  • 2,815
  • 1
  • 23
  • 31