2012-02-24 202 views
1

我使用代碼:Map.lookup - 類型聲明錯誤

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

在這裏,我要檢查詮釋的地圖是否存在等,如果它存在查找的值。但我得到錯誤:

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 

爲什麼?我檢查了地圖中存在的鑰匙。我該如何解決它?

更新

Thans你的答案,但我真正的代碼是一個有點複雜:

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 

回答

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 
+2

您可以使用'Data.Maybe'中的'fromMaybe'來代替'maybe 0 id'來將表達式簡寫爲:'fromMaybe 0。 Map.lookup鍵$ cache'。 – shang 2012-02-24 09:33:57

+0

我已更新我的問題。你可以看看嗎? – demas 2012-02-24 10:25:23

+1

爲了在Map中使用數據類型作爲鍵,它必須是Ord類型類的實例(即它必須是可排序的)。要自動爲您的Coord數據類型派生Ord實例,只需將它添加到派生子句中:'data Coord = Coord Int Int派生(Show,Ord)' – 2012-02-24 10:31:05

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

的類型簽名,在你的情況,

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

也就是說,它並不認爲關鍵是在地圖上(它會給你Nothing如果不是,Just 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

1

要解決新問題,請使用

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

member需要「可排序」k以便實際查找某種東西。對於像Coord(與(Int, Int)同構)的簡單結構,Haskell編譯器可以自己計算出訂單。

順便說一句:我認爲如果你的第一個問題已經解決了,並且你有了新的問題,你應該開一個新的問題,因爲你只能接受一個答案,這對於幫助你的人來說並不公平第一部分。