Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return Data.Map from function

Tags:

haskell

This function works:

serialExpansion num = Map.fromList (zip (listOfSimpleDividers num) (powers num))

but when i tying:

serialExpansion :: Int -> Map
serialExpansion num = Map.fromList (zip (listOfSimpleDividers num) (powers num))

i get the error:

simplifier.hs:46:26: Not in scope: type constructor or class `Map'

How must I declare the function?

like image 1000
ceth Avatar asked Dec 06 '10 09:12

ceth


2 Answers

Map is a parameterized data type (also called an abstract data type). Only when you specify a type for the keys and a type for the values do you get a fully defined type.

For example, a map that lets you look up Strings by Integers has the type Map Integer String.

Also, it seems you've imported Map qualified (as you should). Because of this, you have to use Map.Map instead of just Map in the signature.

Thus, your function should have a signature like

 serialExpansion :: Int -> Map.Map Key Value

where Key is the key data type and Value is the value data type. In your case, if I were to guess, perhaps you want Int for both Key and Value. To be precise: you want Key to be the same as the type of the elements in the list listOfSimpleDividers num, and Value to be the same as the type of the elements in the list powers num. (It might help to inspect the type signature of Map.fromList if this is unclear).

By now you might be asking: "but if you were able to tell the correct return type of serialExpansion, why can't the compiler?" It can. That's exactly why your first example worked. Since you omitted the type signature, the compiler inferred it from context. As you just experienced, writing type signatures can be a good way to make sure you fully understand your code (instead of relying on type inference).

like image 155
gspr Avatar answered Nov 02 '22 18:11

gspr


Two points to supplement gspr's answer:

It's a common practice to import the type constructor Map unqualified and then import the rest of the module qualified:

import Data.Map (Map)
import qualified Data.Map as Map

This allows you to avoid writing Map.Map in your type signatures everywhere.

Also, in either GHCi or Hugs you can use :t to ask the interactive environment for the inferred type of any function. For example, if I load this file in GHCi:

import Data.Map (Map)
import qualified Data.Map as Map

serialExpansion num = Map.fromList (zip (listOfSimpleDividers num) (powers num))
  where
    powers = undefined
    listOfSimpleDividers = undefined

I get the following:

*Main> :t serialExpansion
serialExpansion :: (Ord k) => t -> Map k a

If you plug in your own definitions of powers and listOfSimpleDividers you'll get a more specific type.

like image 24
Travis Brown Avatar answered Nov 02 '22 17:11

Travis Brown