我是Haskell的新手,我创建了一个允许“用户”将新电影添加到数据库(一个名为Films.txt的文本文件)的函数。
main = do
putStrLn "Insert film title:"
film <- getLine
putStrLn ("Who directed " ++ film ++ "?")
director <- getLine
putStrLn ("What year was " ++ film ++ " released?")
year <- getLine
appendFile "Films.txt" $ (film ++ "\n")
appendFile "Films.txt" $ (director ++ "\n")
appendFile "Films.txt" $ (year ++ "\n")
appendFile "Films.txt" $ (" " ++ "\n")
创建的文本文件的示例是:
Blade Runner
Ridley Scott
1982
The Fly
David Cronenberg
1986
etc...
如果我想只返回某位导演的电影,我将如何逐行搜索此文件。在另一种语言中,我将使用FOR循环逐行搜索.txt文件,直到与搜索词匹配的行为例如“雷德利斯科特”。然后我将返回匹配行上方的行,输出它(电影名称)并继续搜索直到.txt文件完成。
然而在Haskell中,我无法将这个思维过程转换为代码,主要是因为我找不到逐行搜索文件的方法。
由于
答案 0 :(得分:6)
使用您自己的方法,扫描文件以查找名称:
main = do
putStrLn "Enter Director's name"
name <- getLine
base <- readFile "Films.txt" -- base is the whole file contents as a single string
print $moviesBy name $lines base
moviesBy :: String -> [String] -> [[String]]
moviesBy name (title:director:year:_:others) | director == name = [title, director, year]:moviesBy name others
| otherwise = moviesBy name others -- a different director, scan the rest of the file
moviesBy _ _ = [] -- when there's no more records
更详细......
lines base
将行中的文件内容拆分(删除换行符),生成字符串列表。
moviesBy
接受一个字符串作为搜索模式,以及一个字符串列表,它是您文件的内容。从这个文件的创建方式来看,我们希望在每四个第二行中找到导演的名字。这是第一次模式匹配:
moviesBy name (title:director:year:_:others)
这里,(title:director:year:_:others)
匹配至少四个元素的列表,将它们绑定到相关变量(第四个位置_
是一个通配符模式,在这里与空白字符串匹配,这是无对我们很重要)。 others
,作为:
最右边的操作数,因此匹配列表的剩余部分(第4尾,用Lisp的说法)。在管道|
之后,我们在匹配上添加了一个额外的约束,四元组中的第二个元素应该等于导演的关注名称。如果为true,则在输出中插入[title, director, year]
的列表(作为生成规则的右侧部分:
的RHS上的=
的左操作数)和剩余的通过递归调用(该RHS other
的右操作数)检查列表的一部分(:
); otherwise
跳过此四元组,只考虑其余部分。
最后一行中的匹配处理少于四个元素的任何列表(可能是文件的末尾)。由于我们不太可能在如此短的列表中找到更多导演的电影,我们只需返回[]
。
所以,例如,如果我们有一个列表
["Blade Runner", "Ridley Scott", "1982", " ", "Alien", "Ridley Scott", "1979", " "]
然后找我们获得的斯科特电影:
首先,列表与(title:director:year:_:others)
匹配。然后绑定变量:title
是&#34; Blade Runner&#34;,director
是&#34; Riddley Scott&#34;,year
是&#34; 1982&#34 ; others
是["Alien", "Ridley Scott", "1979", " "]
。由于director
等于我们正在寻找的名称,因此我们采用第一条路径并宣布["Blade Runner", "Ridley Scott", "1982"]:moviesBy "Ridley Scott" ["Alien", "Ridley Scott", "1979", " "]
为我们的结果。
接下来,按照递归调用来构造结果列表的尾部。同样,title
是&#34; Alien&#34;,director
&#34; Ridley Scott&#34;,year
是&#34; 1979&#34;并且others
绑定到一个空列表。因此,步骤1中结果列表的尾部是["Alien", "Ridley Scott", "1979"]:moviesBy "Ridley Scott" []
。
最后一次递归调用。我们不能将至少四个元素模式绑定到空列表,所以我们采用匹配字符串和列表的任意组合的最后一个替代moviesBy _ _
,这里的结果是[](递归停止)。因此,步骤2的结果是["Alien", "Ridley Scott", "1979"]:[]
,换句话说,[["Alien", "Ridley Scott", "1979"]]
。并且在头部前面加上1.,函数的总结果为[["Blade Runner", "Ridley Scott", "1982"], ["Alien", "Ridley Scott", "1979"]]
。