3
votes

I am working on the clojure koans and one of the questions in the functions needs further explanation for me to “get it” and have an aha moment. I am able to write the function that satisfies the question. But I don't fully understand why all the bits work.

Clojure> (= 25 ((fn [a b] (b a)) 5 (fn [n] (* n n))))
true

Question 1. I do not understand why this throws an error:

Clojure> (= 25 ((fn [b a] (b a)) 5 (fn [n] (* n n))))
java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn

So the only change in the above is switching the order of b and a. In my brain I read “a function that takes an a and b” or a “b and an a” but how they are used is up to the subsequent statement in the parens. Why does the order matter at this point?

Questions 2.

Clojure> (= 25 ((fn [a] (5 a)) (fn [n] (* n n))))
java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn

Why when I substitute out the value of b for the int it represents do I get an error?

Quentions 3.

((fn [a b] (b a)) 5 (fn [n] (* n n))))

Why does this not throw an error (b a) b in this instance is 5 which is a symbol. The first item in brackets is expected to be a function or a special form unless it is a list?

1

1 Answers

6
votes
  1. look at your expression in the first function:

    (b a)
    

    since b is first, b has to be a function. In your second example, you're trying to pass 5 to b, but 5 is not a function. With descriptive names you can see that you're trying to use 5 as a function:

    ((fn [argument function] (argument function)) ;; problem!!
     5 
     (fn [n] (* n n)))
    

    Remember the evaluation rules for lisps: given this s-expression:

    (f x y z)
    

    evaluate f, x, y, and z, and apply f as a function to x, y, and z.

  2. see answer to 1 -- '5' is not a function. Use descriptive names, and easily spot the problem:

    ((fn [function] (5 function)) ;; problem!!
     (fn [n] (* n n)))
    

    Change to:

       ((fn [a] (a 5))  ;; 'a' and '5' flipped
        (fn [n] (* n n)))
    

    to get this to run.

  3. this isn't a problem: a is 5, b is a function in (b a). With descriptive names it makes more sense:

    ((fn [argument function] (function argument)) 
     5
     (fn [n] (* n n)))