1

I am working with code:

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

Here I want to check the existance of Int in the Map and lookup the value if it exists. But I get error:

 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

Why? I have checked existance of key in the Map. How can I fix it?

Updated

Thans for your answers, but my real code is a little bit complex:

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

I have updated the code like this:

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

But get the next error:

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
ceth
  • 44,198
  • 62
  • 180
  • 289

4 Answers4

7

Map.lookup key cache returns a Maybe Int, not an Int, thus the compile error.

The easiest way to do what you want is to use Map.findWithDefault like so:

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

If you want to use Map.lookup, you can do the following:

test2 :: Int -> Map Int Int -> Int
test2 key cache = maybe 0 id . Map.lookup key $ cache
Grzegorz Chrupała
  • 3,053
  • 17
  • 24
  • 2
    Instead of `maybe 0 id` you can just use `fromMaybe` from `Data.Maybe` to write the expression simply as: `fromMaybe 0 . Map.lookup key $ cache`. – shang Feb 24 '12 at 09:33
  • 1
    In order to use a datatype as a key in a Map it must be an instance of the Ord typeclass (that is it must be sortable). To automatically derive an Ord instance for your Coord datatype, just add it in the deriving clause: `data Coord = Coord Int Int deriving (Show, Ord)` – Grzegorz Chrupała Feb 24 '12 at 10:31
4

the typechecker isn't smart enough to use the semantic fact of your check to eliminate the maybe. Why not

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

which requires fromJust or the more idiomatically

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

or even better

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

or, ideally

test2 key cache = maybe 0 id (Map.lookup key cache)
Philip JF
  • 28,199
  • 5
  • 70
  • 77
2

The type signature of lookup is, in your case,

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

That is, it does not assume that the key is in the map (it'll give you Nothing if it isn't, Just value if it's in there with value value).

Since you're using guards to assert that key is in the map, you could use (!) instead. Its signature is, in your case,

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

It'll throw an error if the key cannot be found, but you're already handling that. In your case you'd have

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

Addendum: Do note, though, that Data.Map already comes with a function that does just what your test2 does, namely

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

You'll see that test2 = findWithDefault 0.

gspr
  • 11,144
  • 3
  • 41
  • 74
1

To fix your new problem, just use

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

member needs a "sortable" key type in order to actually look something up. For easy structures like Coord (which is isomorphic to (Int, Int)) the Haskell compiler can figure out an order by itself.

BTW: I think if your first problem is solved and you have a new one, you should open a new question, as you can accept only one answer, which isn't very fair to the people who helped you with the first part.

Landei
  • 54,104
  • 13
  • 100
  • 195