Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a recursive function local to the let body

I'm trying to make a function in Clojure that is local to the body of a (let ...) function. I tried the following, but (defn ...) defines things in the global namespace.

(let [] (defn power [base exp]
      (if (= exp 0)
        1
        (if (> exp 0)
          ; Exponent greater than 0                                           
          (* base (power base   (- exp 1)))
          ; Exponent less than 0                                              
      (/ (power base (+ exp 1)) base))))
 (println (power -2 3)))

; Function call outside of let body
(println (power -2 3))

Now, I also tried:

(let [power (fn [base exp]
      (if (= exp 0)
        1
        (if (> exp 0)
          ; Exponent greater than 0                                           
      (* base (power base (- exp 1)))
          ; Exponent less than 0                                              
      (/ (power base (+ exp 1)) base))))]
 (println (power -2 3)))

; Function call outside of let body
(println (power -2 3))

But then I get the error:

Exception in thread "main" java.lang.Exception: Unable to resolve symbol: power in this         context (math.clj:6)

How do I make a function whose namespace is local to the let body and can recursively call itself?

like image 560
dbmikus Avatar asked Dec 06 '22 00:12

dbmikus


2 Answers

For this you can use letfn:

 (letfn [(power [base exp]
               (cond 
                 (= exp 0) 
                 1
                 (> exp 0) ; Exponent greater than 0                              
                 (* base (power base (dec exp)))
                 :else ; Exponent less than 0                                     
                 (/ (power base (inc exp)) base)))]
      (print (power -2 3)))

Note that I also changed your nested if-construction to cond, I think it is more readable. Also I changed (+ exp 1) and (- exp 1) to (inc exp) and (dec exp) respectively. You can even improve your function more like using recur and an accumulator argument, but maybe that goes beyond the scope of your question. Also see Brian Carper's comment below.

like image 189
Michiel Borkent Avatar answered Jan 16 '23 07:01

Michiel Borkent


letfn is the best solution for your particular case. However, you can also created a named "anonymous" function like so:

(let [power (fn power [base exp] ...)]
  (println (power -2 3)))

However, this style doesn't allow for mutually recursive functions, which letfn does.

like image 44
harto Avatar answered Jan 16 '23 07:01

harto