Map.lookup - 类型声明错误

时间:2012-02-24 09:08:46

标签: haskell

我正在处理代码:

test2 :: Int -> Map Int Int -> Int
test2 key cache 
      | Map.member key cache = Map.lookup key cache
      | otherwise = 0

这里我想检查Map中Int的存在并查找值(如果存在)。但我得到错误:

 Couldn't match expected type `Int' with actual type `Maybe a0'
    In the return type of a call of `Map.lookup'
    In the expression: Map.lookup key cache
    In an equation for `test2':
        test2 key cache
          | member key cache = Map.lookup key cache
          | otherwise = 0

为什么呢?我已经检查了地图中密钥的存在。我该如何解决?

更新

渴望得到答案,但我的真实代码有点复杂:

data Coord = Coord Int Int deriving (Show)

calculation :: Coord -> Map Coord Integer -> Integer
calculation coord cache
           | corner coord = 0
           | side coord = 1
           | Map.member coord cache = Map.lookup key cache
           | otherwise = (calculation (move_right coord) cache) + (calculation (move_down coord) cache)
           where (Coord x y) = coord

我更新了这样的代码:

calculation :: Coord -> Map Coord Integer -> Integer
calculation coord cache
           | corner coord = 0
           | side coord = 1
           | Map.member coord cache = Map.findWithDefault (calculation (move_right coord) cache) + (calculation (move_down coord) cache) coord cache
           where (Coord x y) = coord

但是得到下一个错误:

problem_15.hs:21:14:
    No instance for (Ord Coord)
      arising from a use of `member'
    Possible fix: add an instance declaration for (Ord Coord)
    In the expression: member coord cache
    In a stmt of a pattern guard for
                 an equation for `calculation':
        member coord cache
    In an equation for `calculation':
        calculation coord cache
          | corner coord = 0
          | side coord = 1
          | member coord cache
          = findWithDefault (calculation (move_right coord) cache)
          + (calculation (move_down coord) cache) coord cache
          where
              (Coord x y) = coord

problem_15.hs:21:39:
    Couldn't match expected type `Integer'
                with actual type `k0 -> Map k0 a0 -> a0'
    In the return type of a call of `findWithDefault'
    In the first argument of `(+)', namely
      `findWithDefault (calculation (move_right coord) cache)'
    In the expression:
        findWithDefault (calculation (move_right coord) cache)
      + (calculation (move_down coord) cache) coord cache

4 个答案:

答案 0 :(得分:7)

Map.lookup key cache返回一个Maybe Int,而不是Int,因此编译错误。

执行所需操作的最简单方法是使用Map.findWithDefault,如下所示:

test2 :: Int -> Map Int Int -> Int
test2 key cache = Map.findWithDefault 0 key cache

如果您想使用Map.lookup,可以执行以下操作:

test2 :: Int -> Map Int Int -> Int
test2 key cache = maybe 0 id . Map.lookup key $ cache

答案 1 :(得分:4)

typechecker不够智能,无法使用支票的语义事实来消除可能。为什么不

test2 key cache 
  | Map.member key cache = fromJust $ Map.lookup key cache
  | otherwise = 0

需要fromJust或更具惯用性

test2 key cache 
  | Map.member key cache = cache ! key
  | otherwise = 0

甚至更好

test2 key cache = case Map.lookup key cache of
     Just x  -> x
     Nothing -> 1

或者,理想情况下

test2 key cache = maybe 0 id (Map.lookup key cache)

答案 2 :(得分:2)

lookup的类型签名,在您的情况下,

lookup :: Int -> Map Int Int -> Maybe Int

也就是说,它不会假设密钥在地图中(如果密钥不在,它会给你NothingJust value如果它在那里有值value )。

由于您正在使用警卫断言地图中的 键,因此您可以使用(!)代替。在您的情况下,它的签名是

(!) :: Map Int Int -> Int -> Int

如果无法找到密钥,它会抛出error,但您已经在处理它了。在你的情况下,你有

test2 :: Int -> Map Int Int -> Int
test2 key cache 
      | Map.member key cache = cache Map.! key
      | otherwise = 0

附录:请注意,Data.Map已经附带了一个与test2完全相同的功能,即

findWithDefault :: Ord k => a -> k -> Map k a -> a

您会看到test2 = findWithDefault 0

答案 3 :(得分:1)

要修复新问题,请使用

data Coord = Coord Int Int deriving (Show, Ord)

member需要一个“可排序”键类型才能真正查找内容。对于像Coord这样简单的结构(与(Int, Int)是同构的),Haskell编译器可以自己计算出一个顺序。

顺便说一句:我想如果你的第一个问题得到解决并且你有一个新的问题,你应该开一个新的问题,因为你只能接受一个答案,这对于第一个帮助你的人来说不是很公平。一部分。