我正在尝试在Haskell中编写一个可以从文本文档中过滤掉不需要的关键字的程序.文本文档包含有关人员的信息,例如姓名,年龄和城市,我想过滤掉与不符合关键字的人相关的所有信息.
数据库看起来像这样:
"Eric" 27 "London"
"Josefine" 34 "Stockholm"
"Hans" 50 "London"
Run Code Online (Sandbox Code Playgroud)
所以如果关键字是"伦敦",我想要以下输出:
"Eric" 27 "London"
"Hans" 50 "London"
Run Code Online (Sandbox Code Playgroud)
我已经尝试了一些不同的方法来存储信息并过滤掉不需要的人,但我现在对如何做到这一点毫无头绪.
只需使用Prelude中的点点滴滴即可完成此练习.首先让我们将您的文本解析为更有条理的内容:
data Person = Person {
personName :: String,
personAge :: Int,
personLocation :: String
}
parse :: String -> [Person]
parse txt = let rows = map words (lines txt)
in map (\[name, age, location] -> Person name (read age) location) rows
Run Code Online (Sandbox Code Playgroud)
我正在使用神奇的力量map :: (a -> b) -> [a] -> [b]深入研究所产生的列表lines.我正在映射它的lambda函数是部分的 - 如果任何输入行的格式不正确,它将使程序崩溃.在现实世界的代码中,我肯定会通过在我的解析器中构建错误处理来更优雅地处理故障:我将返回类型更改为Either String [Person]并返回,Left "an error message"如果它无法解析.像Parsec这样的解析器库提供开箱即用的错误处理.
现在我们可以直截了当地filter :: (a -> Bool) -> [a] -> [a]说出我们不感兴趣的人.
londonPeople :: [Person] -> [Person]
londonPeople = filter (\p -> personLocation p == "London")
Run Code Online (Sandbox Code Playgroud)
打印输出也很简单:
personToString :: Person -> String
personToString (Person name age location) = unwords [name, show age, location]
Run Code Online (Sandbox Code Playgroud)
我们可以将这些碎片整合到一个程序中:
input = "Eric 27 London\nJosefine 34 Stockholm\nHans 50 London"
main = let people = parse input
output = map personToString (londonPeople people)
in putStrLn (unlines output)
Run Code Online (Sandbox Code Playgroud)
运行它会产生预期的输出.
$ runhaskell people.hs
Eric 27 London
Hans 50 London
Run Code Online (Sandbox Code Playgroud)