Search code examples
dictionaryhaskelltypescastingmap-function

Haskell map function over a map (fromList) to new type


I'm trying to map a function over a Map (from Data.Map) instance to convert it to a new type of Map. Specifically I've got 2 types of Maps:

type Scope = Map.Map String AExpr
type Row = Map.Map String Value

A function that maps AExpr to Value ( given its first argument Scope ):

evalAExpr :: Scope -> AExpr -> Value

And an instance of type Scope, say x, for which I want to map the function evalAExpr over to obtain an instance of type Row.

According to the documentation this should be possible simply using:

map :: (a -> b) -> Map k a -> Map k b

So in my case that would be:

x :: Scope
evalAExpr :: Scope -> AExpr -> Value
y = map (evalAExpr x) x :: Row

Since Scope has type Map String AExpr, and Row has type Map String Value.

Yet, I'm getting the following error:

* Couldn't match type `Map.Map String AExpr' with `[AExpr]'
  Expected type: [AExpr]
    Actual type: Scope
* In the second argument of `map', namely `g'
  In the expression: map (evalAExpr g) g
  In an equation for r': r' = map (evalAExpr g) g    | 43 |         r' = map (evalAExpr g) g

No idea why it insists on expecting a list of AExpr instead of a Map String AExpr ( = Scope ). If anyone could help me out on what I'm doing wrong and how to go about this it'd be much appreciated!


Solution

  • You're using the wrong map.

    The map that is in scope "by default" (which means that it comes from auto-imported module Prelude) is for lists:

    map :: (a -> b) -> [a] -> [b]
    

    If you want to use one for Map, you need to import it. You can either shadow the list version like this:

    import Data.Map (map)
    

    Or, a better approach, import Data.Map as qualified, and use map with qualification:

    import qualified Data.Map as M
    
    y = M.map (evalAExpr x) x
    

    Alternatively, you can use fmap, which is a general version of map that works for any data structure that can be "mapped over". Such structures are called "functors", and Map is one of them:

    y = fmap (evalAExpr x) x
    

    You can also use it in operator form:

    y = evalAExpr x <$> x
    

    Operator <$> is just an alias for fmap.