Reputation: 145
I am trying to write a linear interpolation in Haskell:
linear_interpolation:: [(Double, Double)] -> Double -> Maybe Double
linear_interpolation list x
| x1 /= Nothing && x2 /= Nothing && y1 /= Nothing && y2 /= Nothing
= Just (y1+ (y2-y1)*(x - x1)/(x2 - x1))
| otherwise = Nothing
where
x2 = find (> x) (x_list list)
x1 = max_elem $ filter (< x) (x_list list)
y1 = lookup x1 list
y2 = lookup x2 list
But I get this error:
• Couldn't match type ‘Double’ with ‘Maybe Double’
Expected: [(Maybe Double, Double)]
Actual: [(Double, Double)]
• In the second argument of ‘lookup’, namely ‘list’
In the expression: lookup x2 list
In an equation for ‘y2’: y2 = lookup x2 list
|
29 | y2 = lookup x2 list
| ^^^^
I don't really understand what's going on, because lookup type is like that:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
P.S
The same problem for y1, x1, x2
Upvotes: 0
Views: 52
Reputation: 116174
Testing x1 /= Nothing
doesn't change the type of x1
, which is still Maybe Double
, so we can't perform arithmetic operations on x1
.
For this reason, testing x1 /= Nothing
, isNothing x1
, or isJust x1
is most likely to be the wrong thing to do. Most often what we really need to use is pattern matching:
linear_interpolation
:: [(Double, Double)] -> Double -> Maybe Double
linear_interpolation list x = let
x2 = find (> x) (x_list list)
x1 = max_elem $ filter (< x) (x_list list)
in case (x1, x2) of
(Just x1', Just x2') -> let
y1 = lookup x1' list
y2 = lookup x2' list
in case (y1, y2) of
(Just y1', Just y2') ->
Just (y1' + (y2' - y1')*(x - x1')/(x2' - x1'))
-> Nothing
_ -> Nothing
Here, x1',x2',y1',y2'
will have the wanted type Double
.
The nested let
and case
is not so readable. In this case, it's simpler if we exploit the Maybe
monad and use do
notation.
linear_interpolation
:: [(Double, Double)] -> Double -> Maybe Double
linear_interpolation list x = do
x2 <- find (> x) (x_list list)
x1 <- max_elem $ filter (< x) (x_list list)
y1 <- lookup x1 list
y2 <- lookup x2 list
Just (y1 + (y2 - y1)*(x - x1)/(x2 - x1))
Here, using <-
, we make x1,x2,y1,y2 :: Double
removing the Maybe
from the type. The Nothing
case is automatically dealt with, which makes it rather convenient.
Upvotes: 2