haskell 如何避免查找中的类型不匹配?

rsaldnfx  于 2022-12-27  发布在  其他
关注(0)|答案(1)|浏览(203)

我试图写一个线性插值在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

但我得到这个错误:

• 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
   |                        ^^^^

我真的不明白是怎么回事,因为查找类型是这样的:

lookup :: Eq a => a -> [(a, b)] -> Maybe b

附言
对于y1,x1,x2也有同样的问题

c86crjj0

c86crjj01#

测试x1 /= Nothing不会改变x1的类型,它仍然是Maybe Double,所以我们不能在x1上执行算术运算。
因此,测试x1 /= NothingisNothing x1isJust x1很可能是错误的。通常我们真正需要使用的是 * 模式匹配 *:

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

这里,x1',x2',y1',y2'将具有所需的类型Double
嵌套的letcase不是那么可读,在这种情况下,如果我们利用Maybe单子并使用do表示法会更简单。

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))

这里,我们使用<-,使x1,x2,y1,y2 :: Double从类型中删除MaybeNothing的情况会自动处理,这使得它非常方便。

相关问题