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

时间:2013-07-19 22:17:57

标签: parsing haskell state

如何在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()

为了给出(过度简化的)具体示例,输入将包含需要通过某些规则进行关联的行。在这里,程序应检测到键'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

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

1 个答案:

答案 0 :(得分:5)

来自insert :: Ord k => k -> a -> Map k a -> Map k a

Data.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..]

addLines获取要存储的行列表,返回Map,行号作为行的键。如果您只是将一大堆文字投入String,请使用lines :: String -> [String]将其分成几行。

正如Gabriel在评论中所建议的,将一系列行转换为Map的更好方法是

addLines = M.fromList . zip [1..]

注意:第一个函数允许您传入初始Map而不是M.empty,但使用M.unionMap与第二个函数组合可能会更快。