I am trying to numerically integrate a function in Haskell using the trapezoidal rule, returning an anti-derivative which takes arguments a, b, for the endpoints of the interval to be integrated.
integrate :: (Float -> Float) -> (Float -> Float -> Float)
integrate f
= \ a b -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b)
where
d = (b - a) / n
n = 1000
In the above, I use
n - for the number of subintervals
d - for the width of each subinterval
This almost works, except for the bound arguments a,b in the lambda. I get the error message:
Not in scope: `b'
Not in scope: `a'
I can understand that the scope of a,b is restricted to just that lambda expression, but is there a workaround in Haskell so that I don't have to write (b-a)/n for each occurrence of d in the above?
You have a lot of work-arounds.
If you don't know any binding syntax except lambda expressions you can do this (which I love the most because of its theoretical beauty, but never use because of its syntactic ugliness):
integrate f
= \a b -> (\d -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b))
((b - a) / n)
where
n = 1000
If you like definitions and only know where
-syntax you can do this:
integrate f = go
where
n = 1000
go a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b)
where
d = (b - a) / n
If you also know let
-syntax, you can do this:
integrate f =
\a b -> let d = (b - a) / n
in d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b)
where
n = 1000
Finally, if you remember that a -> (b -> c -> d)
is the same as a -> b -> c -> d
, you can do the obvious:
integrate f a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b)
where
n = 1000
d = (b - a) / n
You're thinking you need to return a function which takes two Float
s and returns a Float
, but actually that's no different to taking two extra Float
arguments in your integrate
function and using currying (i.e. just don't provide them and the return type will be Float -> Float -> Float
).
So you can rewrite your function like this
integrate :: (Float -> Float) -> Float -> Float -> Float
integrate f a b
= d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b)
where
d = (b - a) / n
n = 1000
Or you could use let ... in
instead of where
:
integrate f
= \a b ->
let d = (b - a / n)
n = 1000
in d * sum [ f (a + d * k) | k <- [0..n] ] - d/2.0 * (f a + f b)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With