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汤更容易维护.
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..]
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
用来组合Map
s和第二个函数可能会更快.