非详尽模式:Int - > Int - > [电影] - > [电影]

时间:2016-03-04 22:18:50

标签: haskell

我想创建一个函数,返回给定年份范围内的电影列表。例如,鉴于我有一系列电影,我想找到2010年至2014年出版的所有电影。这是我的代码:

type Rating = (String, Int)
type Title = String
type Director = String
type Year = Int
type Film = (Title, Director, Year,[Rating])

testDatabase :: [Film]
testDatabase = [("Blade Runner","Ridley Scott",1982,[("Amy",5), ("Bill",8), ("Ian",7), ("Kevin",9), ("Emma",4), ("Sam",7), ("Megan",4)]),
            ("The Fly","David Cronenberg",1986,[("Megan",4), ("Fred",7), ("Chris",5), ("Ian",0), ("Amy",6)]),
            ("Psycho","Alfred Hitchcock",1960,[("Bill",4), ("Jo",4), ("Garry",8), ("Kevin",7), ("Olga",8), ("Liz",10), ("Ian",9)]),
            ("Body Of Lies","Ridley Scott",2008,[("Sam",3), ("Neal",7), ("Kevin",2), ("Chris",5), ("Olga",6)]),
            ("Avatar","James Cameron",2009,[("Olga",1), ("Wally",8), ("Megan",9), ("Tim",5), ("Zoe",8), ("Emma",3)]),
            ("Titanic","James Cameron",1997,[("Zoe",7), ("Amy",1), ("Emma",5), ("Heidi",3), ("Jo",8), ("Megan",5), ("Olga",7), ("Tim",10)]),
            ("The Departed","Martin Scorsese",2006,[("Heidi",3), ("Jo",8), ("Megan",5), ("Tim",3), ("Fred",5)]),
            ("Aliens","Ridley Scott",1986,[("Fred",9), ("Dave",6), ("Amy",10), ("Bill",7), ("Wally",1), ("Zoe",5)]),
            ("Kingdom Of Heaven","Ridley Scott",2005,[("Garry",3), ("Chris",7), ("Emma",5), ("Bill",1), ("Dave",3)]),
            ("E.T. The Extra-Terrestrial","Steven Spielberg",1982,[("Ian",9), ("Amy",1), ("Emma",7), ("Sam",8), ("Wally",5), ("Zoe",6)]),
            ("Bridge of Spies","Steven Spielberg",2015,[("Fred",3), ("Garry",4), ("Amy",10), ("Bill",7), ("Wally",6)]),
            ("Vertigo","Alfred Hitchcock",1958,[("Bill",8), ("Emma",5), ("Garry",1), ("Kevin",6), ("Olga",6), ("Tim",10)]),
            ("The Birds","Alfred Hitchcock",1963,[("Garry",7), ("Kevin",8), ("Olga",4), ("Tim",8), ("Wally",3)]),
            ("Jaws","Steven Spielberg",1975,[("Fred",3), ("Garry",0), ("Jo",3), ("Neal",9), ("Emma",7)]),
            ("The Martian","Ridley Scott",2015,[("Emma",7), ("Sam",8), ("Wally",5), ("Dave",10)]),
            ("The Shawshank Redemption","Frank Darabont",1994,[("Jo",8), ("Sam",10), ("Zoe",4), ("Dave",7), ("Emma",3), ("Garry",10), ("Kevin",7)]),
            ("Gladiator","Ridley Scott",2000,[("Garry",7), ("Ian",4), ("Neal",5), ("Wally",3), ("Emma",4)]),
            ("The Green Mile","Frank Darabont",1999,[("Sam",3), ("Zoe",4), ("Dave",7), ("Wally",5), ("Jo",5)]),
            ("True Lies","James Cameron",1994,[("Dave",3), ("Kevin",10), ("Jo",0)]),
            ("Super 8","J J Abrams",2011,[("Dave",7), ("Wally",3), ("Garry",5), ("Megan",4)]),
            ("Minority Report","Steven Spielberg",2002,[("Dave",6), ("Garry",6), ("Megan",2), ("Sam",7), ("Wally",8)]),
            ("War Horse","Steven Spielberg",2011,[("Dave",6), ("Garry",6), ("Megan",3), ("Sam",7), ("Wally",8), ("Zoe",8)]),
            ("The Terminal","Steven Spielberg",2004,[("Olga",8), ("Heidi",8), ("Bill",2), ("Sam",6), ("Garry",8)]),
            ("Star Wars: The Force Awakens","J J Abrams",2015,[("Olga",6), ("Zoe",6), ("Bill",9), ("Sam",7), ("Wally",8), ("Emma",8)]),
            ("Hugo","Martin Scorsese",2011,[("Sam",9), ("Wally",3), ("Zoe",5), ("Liz",7)])]

filmsInRangeOfYears :: Int -> Int -> [Film] -> [Film]
filmsInRangeOfYears _ _ [] = []
filmsInRangeOfYears minYear maxYear [(title, director, year, rating)] = filter(\(_,_,year,_) -> year >= minYear && year <=maxYear) [(title, director, year, rating)]

但是,我一直收到这个错误

**Non-exhaustive patterns in function filmsInRangeOfYears**

在网上浏览后,我仍然不明白如何解决这个错误;从我的理解,我需要更多的模式来填补所有可能的情况,但我使用的仍然给了我相同的结果。如果有人能帮助我,我会非常感激

编辑:添加了一个电影的示例列表

3 个答案:

答案 0 :(得分:2)

在第一行:

filmsInRangeOfYears _ _ [] = []

你匹配空列表。在第二行(省略一些细节):

filmsInRangeOfYears minYear maxYear [(...)] = ...

您要匹配列表由一个项目组成。你错过了对x:xs的匹配:头部和非空尾部。

答案 1 :(得分:2)

<强>问题

这里的问题是你是一个单例列表的模式匹配。 当你调用函数时,它首先尝试将模式匹配到空列表,如果没有它移动到单例列表的下一个模式,如果列表有多个元素,它将移动到下一个模式,在这种情况下,因此没有导致错误。

解决方案

filmsInRangeOfYears :: Int -> Int -> [Film] -> [Film]
filmsInRangeOfYears minYear maxYear = filter(\(_,_,year,_) -> year >= minYear && year <= maxYear)

解释 - 当类型签名有三个

时,两个参数的模式匹配

因为我们的函数体正在使用带谓词和列表的过滤函数,如果我们只给它一个谓词,我们将得到一个部分应用的函数这个函数期待一个列表就像我们的电影InRangeOfYears函数是它的最后一个参数。此方法与执行以下操作相同。 filmsInRangeOfYears minYear maxYear xs = filter(...) xs

注意我们也可以删除空列表模式匹配,因为如果没有元素符合谓词,filter将返回一个空列表。

答案 2 :(得分:1)

我对你在这里要做的事情感到有点困惑。我认为这是你的初衷:

filmsInRangeOfYears :: Int -> Int -> [Film] -> [Film]
filmsInRangeOfYears _ _ [] = []
filmsInRangeOfYears minYear maxYear ((title, director, year, rating):tail) = 
    if year >= minYear && year <= maxYear
    then (title, director, year, rating):filmsInRangeOfYears minYear maxYear tail
    else filmsInRangeOfYears minYear maxYear tail

您无法在那里使用filterfilter已完成所有操作,因此只需将您的功能转换为

即可
filmsInRangeOfYears :: Int -> Int -> [Film] -> [Film]
filmsInRangeOfYears minYear maxYear films = filter (\(_,_,year,_) -> year >= minYear && year <=maxYear) films

回到错误原因,为了详尽地匹配列表,通常会处理两种情况:

a [] = ...
a (head:tail) = ...

这是空列表和非空列表,匹配为headtail。这两种模式涵盖了列表可能采用的所有可能值。在您的代码中,您为空列表和包含单个元素的列表编写了规则,该元素的组件与titledirector等匹配。你还有一个案件要处理,一个长度为&gt; = 2的列表。

尽管如此,考虑到filter的误解,这仍然是错误的。