I used the code provided at the bottom of this document: http://www.cs.dartmouth.edu/~doug/pearl.ps.gz
import Data.Ratio
infixl 7 .*
default (Integer, Rational, Double)
-- constant series
ps0, x:: Num a => [a]
ps0 = 0 : ps0
x = 0 : 1 : ps0
-- arithmetic
(.*):: Num a => a->[a]->[a]
c .* (f:fs) = c*f : c.*fs
instance Num a => Num [a] where
negate (f:fs) = (negate f) : (negate fs)
(f:fs) + (g:gs) = f+g : fs+gs
(f:fs) * (g:gs) = f*g : (f.*gs + fs*(g:gs))
fromInteger c = fromInteger c : ps0
instance Fractional a => Fractional [a] where
recip fs = 1/fs
(0:fs) / (0:gs) = fs/gs
(f:fs) / (g:gs) = let q = f/g in
q : (fs - q.*gs)/(g:gs)
-- functional composition
compose:: Num a => [a]->[a]->[a]
compose (f:fs) (0:gs) = f : gs*(compose fs (0:gs))
revert::Fractional a => [a]->[a]
revert (0:fs) = rs where
rs = 0 : 1/(compose fs rs)
-- calculus
deriv:: Num a => [a]->[a]
deriv (f:fs) = (deriv1 fs 1) where
deriv1 (g:gs) n = n*g : (deriv1 gs (n+1))
integral:: Fractional a => [a]->[a]
integral fs = 0 : (int1 fs 1) where
int1 (g:gs) n = g/n : (int1 gs (n+1))
expx, cosx, sinx:: Fractional a => [a]
expx = 1 + (integral expx)
sinx = integral cosx
cosx = 1 - (integral sinx)
instance Fractional a => Floating [a] where
sqrt (0:0:fs) = 0 : sqrt fs
sqrt (1:fs) = qs where
qs = 1 + integral((deriv (1:fs))/(2.*qs))
-- tests
test1 = sinx - sqrt(1-cosx^2)
test2 = sinx/cosx - revert(integral(1/(1+x^2)))
iszero n fs = (take n fs) == (take n ps0)
main = (iszero 30 test1) && (iszero 30 test2)
When trying to run it, I get the following errors:
Prelude> :load pearl.hs
[1 of 1] Compiling Main ( pearl.hs, interpreted )
pearl.hs:22:10:
Could not deduce (Eq a) arising from the literal ‘0’
from the context (Num [a], Fractional a)
bound by the instance declaration at pearl.hs:20:10-39
Possible fix: add (Eq a) to the context of the instance declaration
In the pattern: 0
In the pattern: 0 : fs
In an equation for ‘/’: (0 : fs) / (0 : gs) = fs / gs
pearl.hs:28:17:
Could not deduce (Eq a) arising from the literal ‘0’
from the context (Num a)
bound by the type signature for
compose :: Num a => [a] -> [a] -> [a]
at pearl.hs:27:11-32
Possible fix:
add (Eq a) to the context of
the type signature for compose :: Num a => [a] -> [a] -> [a]
In the pattern: 0
In the pattern: 0 : gs
In an equation for ‘compose’:
compose (f : fs) (0 : gs) = f : gs * (compose fs (0 : gs))
pearl.hs:31:9:
Could not deduce (Eq a) arising from the literal ‘0’
from the context (Fractional a)
bound by the type signature for
revert :: Fractional a => [a] -> [a]
at pearl.hs:30:9-32
Possible fix:
add (Eq a) to the context of
the type signature for revert :: Fractional a => [a] -> [a]
In the pattern: 0
In the pattern: 0 : fs
In an equation for ‘revert’:
revert (0 : fs)
= rs
where
rs = 0 : 1 / (compose fs rs)
pearl.hs:49:15:
Could not deduce (Eq a) arising from the literal ‘0’
from the context (Fractional [a], Fractional a)
bound by the instance declaration at pearl.hs:48:10-37
Possible fix: add (Eq a) to the context of the instance declaration
In the pattern: 0
In the pattern: 0 : 0 : fs
In an equation for ‘sqrt’: sqrt (0 : 0 : fs) = 0 : sqrt fs
pearl.hs:57:1:
Couldn't match expected type ‘IO t0’ with actual type ‘Bool’
In the expression: main
When checking the type of the IO action ‘main’
Failed, modules loaded: none.
I've changed "import Ratio" to "import Data.Ratio", but then got stuck.
GHC's "possible fix" messages are often very misleading, but this one is spot on. Why didn't you try it?
Possible fix: add
(Eq a)
to the context of the instance declaration
i.e.
instance (Fractional a, Eq a) => Fractional [a] where
...
This is needed because some Num
instances may not allow equality comparison (in fact this instance is an excellent example, since the infinite lists can never be proven equal in finite time!) but when writing a pattern (0:fs) / (0:gs) -> ...
, you need an equality check to confirm the head is in fact zero. Lists of course have an Eq
instance, but really those aren't general lists you're dealing with but always-infinite lists (otherwise those patterns are inexhaustive), so you should use a newtype wrapper without Eq
instance instead, like
newtype Series a = Series {getSeries :: [a]}
In þe olden days, Eq
used to be a superclass of Num
, so the [a]
would compile without complaints. But as I said, this wasn't really good.