Haskell: Writing a function that can take Ints or Doubles
Date: 2012-06-05 00:10:29

In my continued reading of SICP I wanted to recreate a 'sum' function used to demonstrate a function which could take another function as one of its parameters.

In Scheme the function is defined like this:

[source,scheme]
----

(define (sum term a next b)
  (if (> a b)
      0
      (+ (term a)
         (sum term (next a) next b))))
----

And can be used like this to sum the values between two numbers:

[source,scheme]
----

(define (identity x) x)

(define (sum-integers a b)
  (sum identity a inc b))
----

[source,text]
----

> (sum-integers 1 10)
55
----

I translated it into Haskell as the following:

[source,haskell]
----

sicpSum :: (Int -> Int) -> Int -> (Int -> Int) -> Int -> Int
sicpSum term a next b | a > b = 0
                      | otherwise = term a + sicpSum term (next a) next b
----

The 'sum-integers' function translates like this:

[source,haskell]
----

sumIntegers :: Int -> Int -> Int
sumIntegers a b = sicpSum id a inc b
----

[source,text]
----

> sumIntegers 1 10
55
----

It works fine with integers but later on in the chapter it's used to define a function which returns a double:

[source,scheme]
----

(define (pi-sum a b)
  (define (pi-term x)
    (/ 1.0 (* x (+ x 2))))
  (define (pi-next x)
    (+ x 4))
  (sum pi-term a pi-next b))
----

[source,text]
----

> (* 8 (pi-sum 1 1000))
3.139592655589783
----

I tried writing my 'piSum' function to call the existing 'sumIntegers':

[source,haskell]
----

piSum a b = sicpSum piTerm a piNext b where
	piTerm x = 1 / (x * (x + 2))
	piNext x = x + 4
----

Which unfortunately doesn't compile because of our use of '/':

[source,text]
----

sicp.hs:124:22:
    No instance for (Fractional Int)
      arising from a use of `piTerm'
    Possible fix: add an instance declaration for (Fractional Int)
    In the first argument of `sicpSum2', namely `piTerm'
    In the expression: sicpSum2 piTerm a piNext b
    In an equation for `piSum':
        piSum a b
          = sicpSum2 piTerm a piNext b
          where
              piTerm x = 1 / (x * x + 2)
              piNext x = x + 4
----

[source,text]
----

> :t (/)
(/) :: Fractional a => a -> a -> a
----

I need to make 'sicpSums' generic enough to take in a Double or Int in order to reuse it here.

Most of the functions I've written have been for very specific types although a lot of the Haskell examples I've come across tend to have very generic type signatures.

I found quite a http://en.wikibooks.org/wiki/Haskell/Classes_and_types#Standard_classes[cool diagram on a Haskell wiki] which shows which types inherit different type classes.

image::{{<siteurl>}}/uploads/2012/06/haskell-classes-small1.png[Haskell classes small,288,link=http://upload.wikimedia.org/wikipedia/commons/thumb/6/69/Classes.svg/480px-Classes.svg.png]

In this case both Int and Double derive from the Num type class so we can redefine 'sicpSum' in terms of that:

[source,haskell]
----

sicpSum :: (Ord a, Num a1) => (a -> a1) -> a -> (a -> a) -> a -> a1
sicpSum term a next b | a > b = 0
                      | otherwise = term a + sicpSum term (next a) next b
----

We had to also make sure that 'a' inherits the 'Ord' type class because of the comparison between a and b that we do on the second line.

'piSum' can then make use of the new 'sicpSum' in its definition:

[source,haskell]
----

piSum :: (Ord a1, Fractional a1) => a1 -> a1 -> a1
piSum a b = sicpSum piTerm a piNext b where
	piTerm x = 1 / (x * (x + 2))
	piNext x = x + 4
----

We can then use it like this:

[source,haskell]
----

> 8 * (piSum 1 1000)
3.139592655589783
----

Obviously this is a very simple example but I haven't written any functions which could take in different types so I thought I'd document how I did it, especially because the diagram of the type classes is really useful!