17

I'm new in Haskell and I need to define an empty Data.map and assigning a "list of integers" (e.g. [1,2,3]) to its keys by using insert function and also updating the values. Then looking up the key values.

What I have tried so far is :

import qualified Data.Map
foo num =
 let
 my_map = Data.Map.empty
 new_map = bar my_map num 1
 in
 Data.Map.lookup 1 new_map
bar my_map num c =
 if c > num then my_map
 else
 Data.Map.insert c [c] my_map
 bar my_map num c+1

This code doesn't work.

Could you have a simple example please?

asked Dec 13, 2013 at 21:22
3
  • 4
    What have you tried so far? Most of the functionality you're looking for is available directly as functions in Data.Map. Commented Dec 13, 2013 at 21:29
  • 1
    @J.Abrahamson I thought it's clear from the OP's post what s/he has tried. Commented Dec 13, 2014 at 4:02
  • @talonx The question was edited 3 days after I wrote my comment. Commented Dec 13, 2014 at 12:53

4 Answers 4

35

People normally import the Data.Map module with this boilerplate:

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

The idea is that since many of the names in the module clash with the Prelude and other modules, you want to use them as qualified names—but not for the Map type itself. And the as Map bit in the second line saves you from having to type as much—you just say Map.map, Map.empty, etc.

Now, the easiest and most common way of constructing a map is to use the fromList function in the module. This constructs a Map from a list of key/value pairs: Map.fromList :: Ord k => [(k, v)] -> Map k v. To construct this list of key/value pairs you can use the full power of Haskell's list processing functions, like in this example:

myMap :: Integer -> Map Integer [Integer]
myMap n = Map.fromList (map makePair [1..n])
 where makePair x = (x, [x])

Example output in GHCI:

>>> myMap 3
fromList [(1,[1]),(2,[2]),(3,[3])]

Note that the Map type even prints itself as a fromList call that would reconstruct it. Why? Because again, this function really is the most common way to build a Map.

In contrast, what you're doing in your code is you're trying to write an imperative-style loop that successively augments an initial empty map with entries one at a time. The Haskell equivalent of loops is list functions. In my version I used the following:

  1. [1..n]—generate a list of the integers from 1 up to n.
  2. map—apply a function to each element of the list.
  3. Map.fromList—build a Map from a list of key/value pairs.

And to further demonstrate that point, if you look at the source code for Map.fromList, it's actually defined using a list fold function.

My advise to you: study lists and the Data.List module first before you tackle Map. In particular:

  1. Learn what functions are available there and what to do.
  2. Study the foldr function from that module—how to use it, and how to write it.
  3. Learn how to write your own versions of map, filter and find in terms of foldr.
answered Dec 14, 2013 at 1:58
Sign up to request clarification or add additional context in comments.

2 Comments

Woow! This is great! Now, I know both using Data.Map in Haskell and this optimized way for doing what I wanted to do.
By the way, do you have any idea about what is wrong with my code?
9

Here's a small program to demonstrate this functionality:

module Main where
import qualified Data.Map as M
main = do
 let emptyMap = M.empty
 mapWithKeys = M.insert 5 "Four" emptyMap
 mapWithKeys' = M.insert 5 "Five" mapWithKeys
 putStrLn $ mapWithKeys' M.! 5

The program will insert "Four" with the key 5, then update the value to "Five", and finally look it up and print it.

answered Dec 13, 2013 at 21:32

1 Comment

You don't need a let for each binding. Just one, with appropriate indentation, is enough.
4

Take a look at Data.Map in base.

While this package does export empty which creates a map, it is easier to build one with

myMap = Data.Map.fromList [(1,"hello"), (3,"goodbye")]

fromList takes a list of (key,value) tuples, and creates a map. This is if you know all the key-value pairs you need at the time of construction.

You can use (!) or Data.Map.lookup to access elements

mttpgn
3716 silver badges17 bronze badges
answered Dec 13, 2013 at 21:36

2 Comments

Why is it better to use fromList than empty?
Sorry, I was wrong. I thought fromList did something a little smarter, but it just strings together a bunch of inserts.
1

Your code suggests you have a few misunderstandings.

import qualified Data.Map
foo num =
 let
 my_map = Data.Map.empty
 new_map = bar my_map num 1
 in
 Data.Map.lookup 1 map

I see you use the map variable but probably meant new_map. Since Haskell defines a function named map, the compiler would tell you a type error. Purely for readability, reducing white space and adding type signatures helps a lot.

-- foo takes an `Int` and produces a Maybe [Int].
foo :: Int -> Maybe [Int]
foo num =
 let my_map = Data.Map.empty
 new_map = bar my_map num 1
 in Data.Map.lookup 1 new_map

Now let's see bar:

bar my_map num c =
 if c > num then my_map
 else
 Data.Map.insert c [c] my_map
 bar my_map num c+1

There are a few problems here:

  • The then and else keywords should be in the same column
  • Your c+1 should have parentheses
  • You need to use a let binding - this is not a mutable map, so by inserting you are actually creating a new map with the new value.

So:

bar :: Map Int [Int] -> Int -> Int -> Map Int [Int]
bar my_map num c =
 if c > num
 then my_map
 else let my_new_map = Data.Map.insert c [c] my_map
 in bar my_new_map num (c+1)
Mikaël Mayer
10.8k7 gold badges67 silver badges106 bronze badges
answered Dec 14, 2013 at 21:04

2 Comments

About new_map, yes, you are right. It was a misspelling that I fixed it now. You are passing a list [1] as the second argument to function "bar", and in the "bar", you are comparing a list to a num (c > num) , how is it possible? What I intended to have about the Data.Map was to have type of Key as "integer", and type of Value as "list of integer". Thank you.
Right, foo was passing [Int] while bar was only accepting Int - my mistake. It wasn't that bar was comparing Int to [Int] (notice the type was always accepting just Int), but I mis-used bar in foo. I'm made a quick adjustment to foo to make it pass just Int and not a singleton list of Ints.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.