Search code examples
haskellhashmaptype-constraints

How to add the Data.HashMap Hashable type constraint?


I've got this working function that counts the occurrences of each element in a list and constructs a map out of it:

import qualified Data.HashMap.Strict as M

counter :: [Int] -> M.HashMap Int Int
counter = foldr (\x -> M.insertWith (+) x 1) mempty

Now I want to generalise this to:

counter :: (Eq k) => [k] -> M.HashMap k Int
counter = foldr (\x -> M.insertWith (+) x 1) mempty

but apparently, I also need the Hashable k type constraint since M.insertWith requires it. I've tried multiple ways of adding the constraint but failed miserably in all attempts1.

Is there a fancy way to add the type constraint or perhaps a language pragma that might help me out?


Full error message:

    • Could not deduce (hashable-1.3.1.0:Data.Hashable.Class.Hashable
                          k)
        arising from a use of ‘M.insertWith’
      from the context: Eq k
        bound by the type signature for:
                   counter :: forall k. Eq k => [k] -> M.HashMap k Int
        at <interactive>:5:1-43
      Possible fix:
        add (hashable-1.3.1.0:Data.Hashable.Class.Hashable
               k) to the context of
          the type signature for:
            counter :: forall k. Eq k => [k] -> M.HashMap k Int
    • In the expression: M.insertWith (+) x 1
      In the first argument of ‘foldr’, namely
        ‘(\ x -> M.insertWith (+) x 1)’
      In the expression: foldr (\ x -> M.insertWith (+) x 1) mempty

1: Adding hashable-1.3.1.0:Data.Hashable.Class.Hashable k (as suggested by the error), Data.Hashable.Class.Hashable k, or M.Hashable k to the type constraint doesn't work. Importing Data.Hashable.Class doesn't work since it's a hidden module.


Solution

  • You import it from the Data.Hashable module, so:

    import Data.Hashable(Hashable)
    
    counter :: (Hashable k, Eq k) => [k] -> M.HashMap k Int
    counter = foldr (\x -> M.insertWith (+) x 1) mempty

    You likely do not expose the hashable package at the moment, in your .cabal file you can list this under the dependencies:

    -- …
    executable …
      -- …
      build-depends:
          base >= 4.7 && < 5
        , hashable >=1.0
        -- …
      -- …