【问题标题】:How to avoid “Exception: Prelude.head: empty list”? - Haskell如何避免“异常:Prelude.head:空列表”? - 哈斯克尔
【发布时间】:2016-10-04 23:23:26
【问题描述】:

大家晚上好,我是haskell的新手。我正在尝试总结读取字符串 Unicode 值的列表并将它们存储在列表中,然后将整数相加。

 getLetterUnicodeValue :: Char -> Int
 getLetterUnicodeValue l = (ord l) - 64

 unicodeValueList :: String -> [Int]
 unicodeValueList x = getLetterUnicodeValue (head x) : unicodeValueList (tail x)

 total :: [Int] -> Int
 total []     = 0
 total x = (head x) + (total (tail x))

当字符串到达​​最后一个字符并且求和函数无法成功执行时,我得到了空列表的错误。 unicodeValueList函数结束时有什么方法可以停止它。

*** Exception: Prelude.head: empty list

【问题讨论】:

  • 是的,你已经为total做了它...

标签: list haskell


【解决方案1】:

避免此异常的最可靠方法是不使用head。相反,您可以使用模式匹配来获取列表的头部和尾部:

unicodeValueList (x:xs) = getLetterUnicodeValue x : unicodeValueList xs

total (x:xs) = x + total xs

这种方式x 和xs 仅在列表非空时可用,并保证您不会意外访问空列表的头部或尾部。

当然,现在您会收到模式匹配不完整的警告:您没有指定当列表为空时应该发生什么。当然之前也是如此,但现在您使用模式匹配,编译器实际上可以看到这一点并警告您(而之前的代码在运行时崩溃而没有任何事先警告)。

那么当列表为空时该怎么办呢?好吧,一个空字符串不包含 unicode 值,对吧?所以当输入为空时它应该返回空列表:

unicodeValueList [] = []

当然,您不需要 模式匹配来修复您的错误。您可以只使用if 来确保仅在列表不为空时调用head 和tail。但如果你这样做,编译器将无法验证你的检查是否有序。如果您使用模式匹配并完全避免不安全的head 和tail 函数,您将永远无法意外访问空列表的头部或尾部,如果您忘记考虑列表可能为空。

【讨论】:

    【解决方案2】:

    是的,您只需要在unicodeValueList 中进行模式匹配

    unicodeValueList :: String -> [Int]
    unicodeValueList [] = []
    unicodeValueList (x:xs) = getLetterUnicodeValue x : unicodeValueList xs
    

    注意这可以写成unicodeValueList = map getLetterUnicodeValue 更好。您收到 head 错误的原因是您的递归没有基本情况 - 它一直在尝试递归,即使它已到达空列表。

    【讨论】:

    • 加一个建议map。 IMO 它比基于递归的解决方案更清晰,并且无点启动。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多