我正在关注"真实世界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类型是最简单的这些解决方案.它允许您返回一个Nothing与null您正在寻找的非常相似的值.但这需要付出代价.您的函数的类型签名变为lastButOne :: [a] -> Maybe a.现在每个调用函数必须不是a a而是a Maybe a,在它得到它的答案之前,它必须告诉Haskell如果答案是什么它将会做什么Nothing.
嗯,这取决于你实际想要做多少错误检查.
我怀疑,鉴于这只是在第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使用它的值).
| 归档时间: |
|
| 查看次数: |
11629 次 |
| 最近记录: |