使用您自己的方法,扫描文件以查找名称:
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 接受一个字符串作为搜索模式,以及一个作为文件内容的字符串列表。从这个文件的创建方式来看,我们希望在每四行中的每一行 second 处找到导演的姓名。这是作为第一个模式匹配完成的:
moviesBy name (title:director:year:_:others)
这里,(title:director:year:_:others) 匹配至少四个元素的列表,将它们绑定到相关变量(第四个位置的_ 是一个通配符模式,这里与空白字符串匹配,这对我们来说并不重要) . others,作为: 的最右边的操作数,因此匹配列表的剩余部分(第 4 个尾部,用 Lisp 的说法)。在管道| 之后,我们对匹配添加了一个额外的约束,即四联体中的第二个元素应该等于所关注的导演姓名。如果为真,则在输出中插入[title, director, year] 的列表(作为: 的左操作数在= 的右侧,生产规则的右侧部分)和列表的剩余部分(@ 987654333@) 通过递归调用检查(右操作数 :); otherwise 这个四联体被跳过,只考虑剩下的部分。
最后一行的匹配处理任何少于四个元素的列表(可能是文件的结尾)。由于我们不太可能在如此短的列表中找到更多导演的电影,因此我们只需返回 []。
例如,如果我们有一个列表
["Blade Runner", "Ridley Scott", "1982", " ", "Alien", "Ridley Scott", "1979", " "]
然后寻找我们获得的斯科特的电影:
首先,列表与(title:director:year:_:others) 匹配。然后绑定变量:title 是“银翼杀手”,director 是“Riddley Scott”,year 是“1982”,others 是 ["Alien", "Ridley Scott", "1979", " "]。由于director 等于我们要查找的名称,因此我们采用第一条路径并声明["Blade Runner", "Ridley Scott", "1982"]:moviesBy "Ridley Scott" ["Alien", "Ridley Scott", "1979", " "] 是我们的结果。
接下来,递归调用构造结果列表的尾部。同样,title 是“Alien”,director“Ridley Scott”,year 是“1979”,others 绑定到一个空列表。因此,第 1 步生成的列表的尾部是 ["Alien", "Ridley Scott", "1979"]:moviesBy "Ridley Scott" []。
最后一次递归调用。我们不能将至少四个元素的模式绑定到空列表,所以我们采用最后一个替代方案,moviesBy _ _,它匹配字符串和列表的任意组合,这里的结果是 [](递归停止)。所以,第 2 步的结果是["Alien", "Ridley Scott", "1979"]:[],换句话说,[["Alien", "Ridley Scott", "1979"]]。并且在 1. 中加上 head,函数的总结果是 [["Blade Runner", "Ridley Scott", "1982"], ["Alien", "Ridley Scott", "1979"]]。