如何在haskell中更新关联映射时处理内容

Rum*_*mca 0 parsing state haskell

如何在Haskell中实现一种在命令式语言中简单易行的转换,因为它可以轻松更新地图及其内容?

while( line = next()) {
  Data d = parse(line);
  if( map.get(d.key) == null) map.put(d.info);
  else map.get(d.key).update(d.info);
}

for(d : map.values) print d.computeResult()
Run Code Online (Sandbox Code Playgroud)

为了给出(过于简化的)具体示例,输入将包含需要通过某些规则关联的行.在这里,程序应检测到键'k'下的值被添加,更新但最终被删除,不应出现在输出中.

[time] ADD key=k, value1=V1
[time] ADD key=k, value2=V2
[time] ADD key=k, value1=ABC
[time] [...]
[time] DEL key=k
[time] ADD key=k2, value1=V1
Run Code Online (Sandbox Code Playgroud)

我应该考虑使用镜头,状态monad,按键(如果可能)或其他东西对数据进行排序?哪个是最干净的方式(至少用boilerplatte)来实现这个?我想知道这样的Haskell脚本是否比awk/sed/grep/xmlstartlet汤更容易维护.

cdk*_*cdk 5

insert :: Ord k => k -> a -> Map k a -> Map k aData.Map做到你想要的.

import qualified Data.Map as M

addLines :: [String] -> M.Map Int String
addLines = foldr (uncurry M.insert) M.empty . parseLines
    where parseLines :: [String] -> [(Int, String)]
          parseLines = zip [1..]
Run Code Online (Sandbox Code Playgroud)

addLines获取要存储的行列表,返回Map带有行号的行作为行的键.如果你只是将一堆文本插入a中String,请使用lines :: String -> [String]将其分成几行.

正如Gabriel在评论中所建议的那样,将一个行列表转换为a的更好方法Map

addLines = M.fromList . zip [1..]
Run Code Online (Sandbox Code Playgroud)

注意:第一个函数允许你传入一个初始Map而不是M.empty,但是M.union用来组合Maps和第二个函数可能会更快.

  • 更好的是,使用`Data.Map.fromList`(也应该更快). (2认同)
  • ...如果你还要添加另一个地图,请使用`Data.Map.union`. (2认同)