2

I'm trying to work through some of the exercises in SICP using Clojure, but am getting an error with my current method of executing Simpson's rule (ex. 1-29). Does this have to do with lazy/eager evalution? Any ideas on how to fix this? Error and code are below:

java.lang.ClassCastException: user$simpson$h__1445 cannot be cast to java.lang.Number at clojure.lang.Numbers.divide (Numbers.java:139)

Here is the code:

(defn simpson [f a b n]
  (defn h [] (/ (- b a) n))
  (defn simpson-term [k]
    (defn y [] (f (+ a (* k h))))
    (cond 
      (= k 0) y
      (= k n) y
      (even? k) (* 2 y)
      :else (* 4 y)))
  (* (/ h 3)
     (sum simpson-term 0 inc n)))
Fred Hsu
  • 108
  • 1
  • 4

1 Answers1

7

You define h as a function of no arguments, and then try to use it as though it were a number. I'm also not sure what you're getting at with (sum simpson-term 0 inc n); I'll just assume that sum is some magic you got from SICP and that the arguments you're passing to it are right (I vaguely recall them defining a generic sum of some kind).

The other thing is, it's almost always a terrible idea to have a def or defn nested within a defn. You probably want either let (for something temporary or local) or another top-level defn.

Bearing in mind that I haven't written a simpson function for years, and haven't inspected this one for algorithmic correctness at all, here's a sketch that is closer to the "right shape" than yours:

(defn simpson [f a b n]
  (let [h (/ (- b a) n)
        simpson-term (fn [k]
                       (let [y (f (+ a (* k h)))]
                         (cond 
                          (= k 0) y
                          (= k n) y
                          (even? k) (* 2 y)
                          :else (* 4 y))))]
    (* (/ h 3)
       (sum simpson-term 0 inc n))))
amalloy
  • 89,153
  • 8
  • 140
  • 205