在Haskell中返回空值而不限制多态性

Pet*_*ter 12 haskell

我正在关注"真实世界Haskell",并且正在进行第2章,其中练习是创建一个"lastButOne"函数,它返回列表中倒数第二个值.我原来的代码是:

lastButOne xs =     if null (tail (tail xs))
                    then head xs
                    else lastButOne (tail xs)
Run Code Online (Sandbox Code Playgroud)

哪个工作正常,除非我给它一个只有1或2个项目的列表.所以我修改了它:

lastButOne xs = if null xs || null (tail xs)
                then head xs
                else
                        if null (tail (tail xs))
                        then head xs
                        else lastButOne (tail xs)
Run Code Online (Sandbox Code Playgroud)

哪个检查它是否只有1个或2个项目,但如果由于调用头部而只有1个项目则会失败.我的问题是我不能想到除了"头xs"以外的任何其他东西,理想情况下我希望它返回null或类似的东西,但我找不到允许该函数仍然存在的"null"多态.

Mat*_*nov 28

也许您正在寻找一种Maybe类型:

lastButOne :: [a] -> Maybe a
lastButOne [x,_] = Just x
lastButOne (_:y:ys) = lastButOne (y:ys)
lastButOne _ = Nothing
Run Code Online (Sandbox Code Playgroud)


Joh*_*ler 10

[我]我真的希望它返回null或类似的东西,但我找不到允许函数仍然是多态的"null".

关于如何使这项工作已经发布了许多答案,所以让我回答一个更为基本的问题:"为什么不存在'空'?"

这是Haskell中类型检查器的哲学的一部分.大多数语言都包含某种形式的特殊值,表示错误或缺少数据.例子包括0,-1 ""(空字符串)的JavaScript null或Ruby的nil.问题在于,这会产生一整类潜在的错误,其中调用函数仅处理"好"值,并且当返回特殊值时程序崩溃或更糟糕地破坏数据.还存在将特殊值作为常规值的问题 - 0实际上是数字而不是失败状态.

在您的问题中,问题可能是框架,"调用的函数是否lastButOne知道如何处理null?"

对于某些其他格式良好的输入没有有效答案的问题在Haskell中非常常见,并且有两个典型的解决方案.第一个来自Erlang:快速而干净地失败.在此解决方案下,调用者有责任确保数据"良好".如果它不是一个程序因错误死亡(或异常被捕获,但是这是比较困难的哈斯克尔那么其他语言)这是最列表功能,如使用的解决方案head,tail等...

另一种解决方案是明确声明该函数可能无法生成良好的数据.该Maybe a类型是最简单的这些解决方案.它允许您返回一个Nothingnull您正在寻找的非常相似的值.但这需要付出代价.您的函数的类型签名变为lastButOne :: [a] -> Maybe a.现在每个调用函数必须不是a a而是a Maybe a,在它得到它的答案之前,它必须告诉Haskell如果答案是什么它将会做什么Nothing.

  • 非常好.对于OP,当你通过RWH工作时,你也会看到`Maybe`使用了更多.然后,当你回到Java或其他任何东西时,你会感到害怕,因为*如果你不小心,程序*中的每个变量都可能变为null. (4认同)

And*_*ffe 5

嗯,这取决于你实际想要做多少错误检查.

我怀疑,鉴于这只是在第2章中,你可能想要忽略这个边缘情况.Haskell本身抛出异常:

Prelude> head []
*** Exception: Prelude.head: empty list
Run Code Online (Sandbox Code Playgroud)

另一种选择,如果这是你必须处理很多情况下,是改变的返回类型lastButOne,以Maybe a和返回Just (head xs)时,它的工作原理,以及Nothing当它失败.但这意味着你总是要处理Maybe monad中的生活 ,这可能并不理想(因为你必须"解开" Just使用它的值).

  • @AndrewJaffe我知道很多Haskellers更喜欢`head`和其他类似的东西来返回一个'Maybe`值. (2认同)