简体   繁体   English

Haskell,如何返回列表而不遇到错误

[英]Haskell, how to return a list without encountering an error

So I'm trying to wrap my head around Haskell with my first project where i have a function encountering an error:所以我试图用我的第一个项目来围绕 Haskell 我有一个 function 遇到错误:

Exception: prelude.head: empty list.例外:prelude.head:空列表。

selectNextGuess :: [[Card]] -> [Card]
selectNextGuess lst
    | length lst >= 1250 = lst !! (div (length lst) 2)
    | otherwise = newGuess 
        where fbList = [[feedback x y | x <- lst, y <- lst]]
              valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x) | x <- lst]
              (_, newGuess) = head(sort valuesList)

Any advice in steering me in the right direction to solve this would be greatly appreciated.任何指导我朝着正确方向解决这个问题的建议将不胜感激。 Cheers干杯

TL;DR: since a list can be empty, and there is no minimal element in the empty list, the way to return a list without the error is to maybe return a list, or rather to return a Maybe list. TL;DR:由于列表可以是空的,并且空列表中没有最小元素,因此返回列表而不会出错的方法是可能返回一个列表,或者更确切地说返回一个Maybe列表。


If you call selectNextGuess [] , lst inside the function selectNextGuess becomes [] .如果调用selectNextGuess [] ,则lst内部的selectNextGuess变为[] Then, valuesList = [(calcValues(group $ sort[feedback yx | y <- lst, y /= x]), x) | x <- [] ] = []然后, valuesList = [(calcValues(group $ sort[feedback yx | y <- lst, y /= x]), x) | x <- [] ] = [] valuesList = [(calcValues(group $ sort[feedback yx | y <- lst, y /= x]), x) | x <- [] ] = [] is also an empty list. valuesList = [(calcValues(group $ sort[feedback yx | y <- lst, y /= x]), x) | x <- [] ] = []也是一个空列表。 And then (_, newGuess) = head (sort valuesList) = head (sort []) = head [] is called.然后(_, newGuess) = head (sort valuesList) = head (sort []) = head []被调用。

But there is no head element in the empty list.但是空列表中没有头元素。 This is what the error message is telling us.这就是错误消息告诉我们的内容。 You called head with [] , which is forbidden, because it has no answer.你用[]调用了head ,这是被禁止的,因为它没有答案。

The usual solution is to make this possibility explicit in the data type.通常的解决方案是在数据类型中明确表示这种可能性。 We either have just one answer, for a non-empty list, or we have nothing :对于非空列表,我们要么只有一个答案,要么一无所有

data Maybe a =  Just a | Nothing

is such built-in type.就是这样的内置类型。 So we can use it, and handle the empty lst explicitly:所以我们可以使用它,并明确地处理空的lst

selectNextGuess :: [[Card]] -> Maybe [Card]
selectNextGuess lst
    | length lst >= 1250 = Just $ lst !! (div (length lst) 2)
    | null lst = Nothing
    | otherwise = Just newGuess 
        where fbList = [[feedback x y | x <- lst, y <- lst]]
              valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x) 
                            | x <- lst]
              (_, newGuess) = head (sort valuesList)

Using null as a guard like that is a bit of an anti-pattern.像这样使用null作为保护有点反模式。 We usually achieve the same goal with the explicit pattern in a separate clause, like我们通常在单独的子句中使用显式模式来实现相同的目标,例如

selectNextGuess :: [[Card]] -> Maybe [Card]
selectNextGuess [] = Nothing
selectNextGuess lst
    | length lst >= 1250 = Just $ lst !! (div (length lst) 2)
    | otherwise = Just newGuess 
        where ......

Using that head... sort... combination to find the minimal element is perfectly fine.使用那个head... sort...组合来找到最小元素是非常好的。 Due to Haskell's lazy evaluation and the library sort being implemented as bottom-up mergesort , it will take O(n) time.由于 Haskell 的惰性评估和库sort被实现为自下而上的mergesort ,它将花费O(n)时间。

There is also a shorter way to write down the same thing,还有一种更短的方法来写下同样的事情,

....
    | otherwise = listToMaybe . map snd $ sort valuesList       -- or, 
                = listToMaybe [ x | (_, x) <- sort valuesList ]  --  whichever you prefer.
        where fbList = .....
              valuesList = .....

Since there is no more than one value "inside" a Maybe _ , the conversion function listToMaybe already takes just head element, implicitly.由于Maybe _ “内部”只有一个值,因此转换 function listToMaybe已经隐式地只采用了head元素。

Moreover, it produces Nothing automatically in the empty list [] case.此外,它会在空列表[]的情况下自动生成Nothing So the explicit pattern clause can be removed, this way.因此可以通过这种方式删除显式模式子句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM