views:

160

answers:

3

I've been learning Haskell recently and was talking to a friend who is working through SICP. We were curious to compare Common Lisp and Scheme and so I decided as an exercise to try to translate exercise 1.29 into Haskell.

This exercise uses a function sigma which represents the mathematical Summation function Sigma. This function takes a function f to apply to each term, a lower bound, a function to apply to each term to get the next term, and an upper bound. It returns the sum of f applied to each term.

simpsonIntegral is supposed to use Simpson's rule to approximate the integral of the function f over the range [a, b] using an "accuracy" n. I'm having trouble getting this function to work because there seems to be something I don't understand about the types involved.

This code will compile with version 6.12.1 of ghc but simpsonIntegral will be given a type context (Integral a, Fractional a) which doesn't make any sense and the function blows up as soon as you call it. I've got this working at one point but what I did was so obviously a hack that I wanted to ask here how this would be handled idiomatically.

How does one idiomatically handle the Integral -> Fractional/Real conversion needed in h? I read a number of things but nothing seemed obvious and clean.

sigma :: (Ord a, Num b) => (a -> b) -> a -> (a -> a) -> a -> b
sigma f a next b = iter a 0
  where
    iter current acc | current > b = acc
                     | otherwise = iter (next current) (acc + f current)

simpsonIntegral f a b n = 1.0 * (h / 3) * (sigma simTerm 0 (1+) n)
  where
    h = (b - a) / n
    simTerm k = (yk k) * term
      where
        yk k = f (a + h * k)
        term =
          case k of
            0 -> 1
            1 -> 1
            otherwise -> if odd k then 4 else 2
+6  A: 
fromIntegral :: (Integral a, Num b) => a -> b

r = fromIntegral i
Justice
Question about fromIntegral. I was trying this but not in the right places per Travis' answer and I thought it wasn't working because according to this http://www.haskell.org/tutorial/numbers.html num does not provide a division operator. Is fromIntegral polymorphic on the return type and ghc infers that I want a Fractional return type?
Andrew Myers
Yes, `fromIntegral` is polymorphic in its return type `b`, in that `b` (the return type) is allowed to be any data type that is a member of the `Num` type class. While the `Num` type class does not provide division, some data types that are members of that type class do provide division, such as `Double`.
Justice
+3  A: 

To follow up on Justice's answer: if you're curious about where to put the fromIntegrals, the following compiles:

simpsonIntegral :: (Integral a, Fractional b) => (b -> b) -> a -> a -> a -> b
simpsonIntegral f a b n = 1.0 * (h / 3) * (sigma simTerm 0 (1+) n)
  where
    h = fromIntegral (b - a) / fromIntegral n
    simTerm k = (yk k) * term
      where
        yk k = f (fromIntegral a + h * fromIntegral k)
        term = 
          case k of
            0 -> 1
            1 -> 1
            otherwise -> if odd k then 4 else 2

And seems to work:

*Main> simpsonIntegral (^3) 0 1 100
0.2533333233333334
*Main> simpsonIntegral (^3) 0 1 1000
0.2503333333323334
Travis Brown
+1  A: 

The problem is that the function "odd" expects it's argument to be an Integral type. The compiler then infers that your variable "k" is of type Integral. But by using the operation "/", the compiler infers "k" to be also of type Fractional. The solution can be as simple as converting "k" to Integer where it's really needed:

if odd (round k) then 4 else 2

If you want to learn more about numeric conversion in Haskell, check Converting_numbers

As a side note, here's another way of writing your sigma function:

sigma f a next b = sum $ map f $ takeWhile (<= b) $ iterate next a
Pedro Rodrigues