首页 > 解决方案 > 为什么我会收到有关空列表的错误?

问题描述

我做了这些功能:

-- Looks up in dict and returns Maybe key
myLookUp :: [(String, [String])] -> String -> String
myLookUp [] val = []
myLookUp ((k, vs):ds) val
  | val `elem` snd (myLast ds) = myCensor val
  | val `elem` vs = k
  | otherwise = myLookUp ds val

-- Given a dict of tuples of strings and list of strings, 
-- should return the last tuple in dict
myLast :: [(String, [String])] -> (String, [String])
myLast [] = error "Empty list"
myLast [x] = x
myLast (x:xs) = myLast xs

哪个可以编译,但是当我尝试对其进行测试时,我收到一条错误消息

ghci> myLookUp [("strength", ["ignorance"]), ("bla", ["blabla", "blabla"])] "aa"

*** Exception: Empty list
CallStack (from HasCallStack):
  error, called at test.hs:103:13 in main:Main

如果我尝试删除我的基本情况myLast [] = error "Empty list",我会收到此错误:

 myLookUp [("strength", ["ignorance"]), ("bla", ["blabla", "blabla"])] "aa"

    *** Exception: test.hs:(104,1)-(105,25): 
    Non-exhaustive patterns in function myLast

我认为这很myLast有效,因为我得到了这个输出:

myLast [("strength", ["ignorance"]), ("bla", ["blabla", "blabla"])]
("bla",["blabla","blabla"])

而且我认为我可以snd在元组上使用来获取列表元素,但是由于我得到了这个错误,我不确定我做错了什么。

标签: haskellrecursion

解决方案


试着更仔细地思考你正在尝试做的事情。此处出现空列表异常的原因是您尝试向 myLast 传递一个可能为空的列表(并且在最后一次迭代时为空)。当输入列表 (ds) 中只剩下一个元素时,您无需检查守卫。您可以通过添加:

| null ds = []

或者检查函数模式中的单个元素。此外,myLast 函数与内置的前奏函数“last”相同,因此可以替换它。还要记住你对 ds 进行空检查的位置,它必须在你尝试使用 ds 之前,但在你第一次检查之后:

myLookUp :: [(String, [String])] -> String -> String
myLookUp [] val = []
myLookUp ((k, vs):ds) val
  | val `elem` vs = k
  | null ds = []
  | val `elem` snd (last ds) = myCensor val
  | otherwise = myLookUp ds val

解决这个问题的一个更好的方法是每次迭代只检查头部的元素,在每次迭代中检查最后一个元素是非常低效的,当你只需要做一次,它会在无论如何,递归循环的最后一次迭代。


推荐阅读