views:

2153

answers:

2

Trying to do exercise 1.16 (iterative version of fast-exp) in "Structure and Interpretation of Computer Programs" with Clojure I came up with this:

(defn fast-it-exp [base exp res]
  (cond (= exp 0) res
  (odd? exp) fast-it-exp base (- exp 1) (* base res)
  :else fast-it-exp base (/ exp 2) (* base base res)))

Trying it out:

user=> (fast-it-exp 0 0 10)
10   ;yep
user=> (fast-it-exp 2 2 2)
1     ;no...
user=> (fast-it-exp 1 1 1)
#<user$fast_it_exp__59 user$fast_it_exp__59@138c63>    ;huh?!

Seems the "odd" part of the cond expression returns a function instead of evaluating. Why? I've tried putting parenthesis around the expressions after the predicates but that seems to be incorrect syntax, this is the best I've been able to come up with. I'm using rev 1146 of Clojure.

+6  A: 

Try this:

 (defn fast-it-exp [base exp res]
  (cond (= exp 0) res
  (odd? exp) (fast-it-exp base (- exp 1) (* base res))
  :else (fast-it-exp base (/ exp 2) (* base base res))))

I have no REPL handy but is looks like what you want.

Phillip Calçado
What the hell, I thought I had tried all possible permutations of parenthesis, but it seems I missed the right one. That worked, thanks a lot Philip. :)
Lars Westergren
Ahum. Why permutations of parentheses? If you want to call a function in Lisp, it has to be the first element of a list; this is how Lisp syntax works.
Svante
In Clojure parentheses after the predicate are optional, as after the (= exp 0) example above. Tried without, but that syntax was ambiguous. Tried with, but I may have had a parentheses around :else which was incorrect. Thought I had tried Philip's version too, but must have done something wrong.
Lars Westergren
Atrocious indentation that.
Luís Oliveira
+4  A: 

Basically, what you wrote could be reformatted as:

(defn fast-it-exp [base exp res]
  (cond
    (= exp 0) res
    (odd? exp) fast-it-exp
    base (- exp 1)
    (* base res) :else
    fast-it-exp base
    (/ exp 2) (* base base res)))

So:

user=> (fast-it-exp 0 0 10) ; (= exp 0) => res
10   ;yep
user=> (fast-it-exp 2 2 2)  ; base => (- exp 1)
1     ;no...
user=> (fast-it-exp 1 1 1)  ; (odd? exp) => fast-it-exp
#<user$fast_it_exp__59 user$fast_it_exp__59@138c63>    ;huh?!
Chris Turner
Ah, I see, that explains the original behaviour, thanks. Also I've managed to do the math correctly now, heh. *blush*
Lars Westergren