更新Haskell地图中的项目,如何?

Kev*_*vin 2 dictionary haskell

我是Haskell的新手,我正试图找出一种合理的方式来写地图(准备解决特定的欧拉项目问题)

我希望编写一个用记录填充Map的函数.但我无法让它发挥作用.

let似乎创造的,而不是局部变量
处理smap作为一个全球性的.

必须有一些方法来做到这一点.

我的代码:

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

smap = Map.fromList [("cocoa",23)]


newdata str n = do  
   let cpy  = Map.insert str n  smap
   cpy 

main = do
     let smap = newdata "pennywise" 16  
     let smap = newdata "krusty" 18  
Run Code Online (Sandbox Code Playgroud)

从评论更新:稍后我想计算一个直角三角形等于周长的方式.因此我认为Map是存储分布计数的好方法,例如p10 - > 5种方式,p15 - > 6种方式等.因此,当程序运行时,它会增加已发现的周长值.

chi*_*chi 5

您无法Map就地修改(因为Haskell是纯函数式语言),但您可以创建一个几乎等于旧映射的新映射,除了一些已修改的条目.

(不要过分担心效率:反直觉,新版本Map不需要旧版本的完整副本.)

例如,假设我们想要计算字符串中每个字符的频率.让我们编写一个函数,给定一个char c,增加其存储在其中的计数Map

import qualified Data.Map.Strict as M

countChar :: Char -> M.Map Char Int -> M.Map Char Int
countChar c oldMap = newMap
   where
   newMap = M.insertWith (+) c 1 oldMap
Run Code Online (Sandbox Code Playgroud)

newMap不需要变量,为清楚起见,上面显示了该变量.

该函数insertWith生成新映射,以便在索引处c存储1,如果旧映射中没有值,或者旧映射中1 + x存在先前值x.

要处理完整的字符串,我们使用递归:

countString :: String -> M.Map Char Int
countString ""     = M.empty
countString (c:cs) = countChar c (countString cs)
Run Code Online (Sandbox Code Playgroud)

GHCi中的小测试:

> countString "here's an example"
fromList [(' ',2),('\'',1),('a',2),('e',4),('h',1),('l',1),('m',1)
         ,('n',1),('p',1),('r',1),('s',1),('x',1)]
Run Code Online (Sandbox Code Playgroud)

对于更高级的解决方案countString,如果需要,也可以重写为折叠.使用左严格折叠也可以提高效率.

countString = foldl' (flip countChar) M.empty
Run Code Online (Sandbox Code Playgroud)

人们甚至可以使用州monad来避免绕过Map.如果您正在学习Haskell,请不要担心这一点,首先要学习如何使用递归,模式匹配和Maps 的一些库函数来解决这些类型的任务.

  • 我不太关心 `insertWith`:很难记住参数传递给组合函数的顺序。如果您需要的不仅仅是 `insert`,我认为 `alter` 提供了一个更好的 API。 (2认同)