在Haskell中使用Data.Map的示例

时间:2013-12-13 21:22:49

标签: haskell hashtable

我是Haskell的新手,我需要定义一个空的Data.map,并使用insert函数并更新值,为其键分配一个“整数列表”(例如[1,2,3])。然后查找关键值。

到目前为止我尝试的是:

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

此代码不起作用。

请问一个简单的例子吗?

4 个答案:

答案 0 :(得分:20)

人们通常使用此样板导入Data.Map模块:

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

这个想法是,由于模块中的许多名称与Prelude和其他模块冲突,您希望将它们用作限定名称,但不能用于Map类型本身。第二行中的as Map位使您无需输入任何内容 - 您只需说Map.mapMap.empty等。

现在,构建地图最简单,最常用的方法是使用模块中的fromList函数。这会从键/值对列表构建MapMap.fromList :: Ord k => [(k, v)] -> Map k v。要构建这个键/值对列表,您可以使用Haskell列表处理函数的全部功能,如下例所示:

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

GHCI中的示例输出:

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

请注意,Map类型甚至会将自身打印为可重建它的fromList调用。为什么?因为这个函数确实是构建Map的最常用方法。

相比之下,你在代码中所做的是你正在尝试编写一个命令式循环,它一次一个地增加一个条目的初始空映射。 Haskell等价的循环是列表函数。在我的版本中,我使用了以下内容:

  1. [1..n] - 生成从1n的整数列表。
  2. map - 将函数应用于列表的每个元素。
  3. Map.fromList - 从键/值对列表中构建Map
  4. 为了进一步证明这一点,如果你看the source code for Map.fromList,它实际上是使用列表折叠函数定义的。

    我建议你:在解决Map之前先研究清单和Data.List模块。特别是:

    1. 了解那里有哪些功能以及可以做什么。
    2. 研究该模块中的foldr函数 - 如何使用它,以及如何编写它。
    3. 了解如何根据map编写自己的filterfindfoldr版本。

答案 1 :(得分:8)

这是一个展示此功能的小程序:

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

程序将使用键5插入“Four”,然后将值更新为“Five”,最后查找并打印出来。

答案 2 :(得分:1)

看看基地的Data.Map

虽然此程序包确实导出了创建地图的empty,但使用

构建地图更容易

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

fromList获取(键,值)元组列表,并创建一个映射。如果您知道构建时需要的所有键值对,那就是这样。

您可以使用(!)lookup来访问元素

答案 3 :(得分:0)

您的代码表明您有一些误解。

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

我看到您使用map变量,但可能意味着new_map。由于Haskell定义了一个名为map的函数,编译器会告诉你一个类型错误。纯粹为了便于阅读,减少空白区域和添加类型签名有很大帮助。

-- 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

现在让我们看看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

这里有一些问题:

  • thenelse关键字应位于同一列
  • 您的c+1应该有圆括号
  • 你需要使用let绑定 - 这不是一个可变的地图,所以通过插入你实际上是用新值创建一个新的地图。

所以:

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)