Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中返回空值而不收缩多态性_Haskell - Fatal编程技术网

在Haskell中返回空值而不收缩多态性

在Haskell中返回空值而不收缩多态性,haskell,Haskell,我将学习“真实世界的Haskell”,并将学习第2章,其中的练习是创建一个“lastButOne”函数,该函数返回列表中倒数第二个值。我最初的代码是: lastButOne xs = if null (tail (tail xs)) then head xs else lastButOne (tail xs) 这很好,除非我给它一个只有1或2项的列表。因此,我将其修改为: lastButOne xs = i

我将学习“真实世界的Haskell”,并将学习第2章,其中的练习是创建一个“lastButOne”函数,该函数返回列表中倒数第二个值。我最初的代码是:

lastButOne xs =     if null (tail (tail xs))
                    then head xs
                    else lastButOne (tail xs)
这很好,除非我给它一个只有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)

它会检查它是否只有1个或2个项目,但如果它只有1个项目,则会由于对head的调用而失败。我的问题是,除了“head xs”之外,我想不出任何其他可以返回的东西,理想情况下我希望它返回null或类似的东西,但是我找不到允许函数仍然是多态的“null”。

为什么不使用模式匹配来处理只有1或2个元素的情况? 比如:

lastButOne :: [a] -> Maybe a
lastButOne [x,y] = Just x
lastButOne (x:y:t) = lastButOne (y:t)
lastButOne  _ = Nothing

可能您正在寻找
可能
类型:

lastButOne :: [a] -> Maybe a
lastButOne [x,_] = Just x
lastButOne (_:y:ys) = lastButOne (y:ys)
lastButOne _ = Nothing

这取决于您实际要执行的错误检查量

我怀疑,鉴于这只是在第2章中,你可能会忽略这个边缘案例。Haskell本身抛出一个异常:

Prelude> head []
*** Exception: Prelude.head: empty list
另一种选择是,如果这是一个需要大量处理的情况,则将
lastButOne
的返回类型更改为
Maybe a
,并在工作时返回
Just(head xs)
,在失败时返回
Nothing
。但这意味着您必须始终在
中生活,这可能并不理想(因为您必须“打开”
值才能使用它)。

Andrew Jaffe提到的“扩展错误处理”示例可能是:

{-# LANGUAGE FlexibleContexts #-} module Main where

import Control.Monad.Error

lastButOne :: MonadError String m => [a] -> m a
lastButOne (_ : y : []) = return y 
lastButOne (_ : t) = lastButOne
lastButOne _ = throwError "Error in lastButOne"
在这种情况下,如果成功,可以返回
类型:
右x
,如果失败,可以返回
左“lastButOne中的错误”
,但是
MonadError字符串m
的许多其他实例也是可能的

也可以阅读更多的可能性

[一] 我确实希望它返回null或类似的东西,但是我找不到允许函数仍然是多态的“null”

关于如何做到这一点,已经有很多答案,所以让我回答一个更基本的问题:“为什么没有‘空’?”

这是Haskell中类型检查器原理的一部分。大多数语言都包含某种形式的特殊值,表示错误或缺少数据。示例包括
0
-1
(空字符串)JavaScripts
null
或Ruby的
nil
。问题是,这会产生一整类潜在的bug,其中调用函数只处理“好”值,当返回一个特殊值时,程序崩溃或更糟地破坏数据。还有一个问题是,特殊值被指定为常规值,即
0
实际上是一个数字,而不是故障状态

在您的问题中,问题可能是这样的:“调用
lastButOne
的函数是否知道如何处理
null
?”

对于某些形式良好的输入,没有有效答案的问题在Haskell中非常常见,有两种典型的解决方案。第一个来自Erlang:快速、干净地失败。在此解决方案下,调用者有责任确保数据“良好”。如果不是这样,则程序会因错误而死亡(或捕获异常,但在Haskell中这比其他语言更困难),这是大多数列表函数使用的解决方案,例如
,等等


另一种解决方案是显式声明函数可能无法生成良好的数据。
类型可能是这些解决方案中最简单的一种。它允许您返回一个值
Nothing
,该值的工作原理与您要查找的
null
非常相似。但这是有代价的。您的函数的类型签名变为
lastButOne::[a]>可能是a
。现在,每个调用函数都必须接受一个
a
,而不是一个
,可能是一个
,在得到答案之前,它必须告诉Haskell如果答案是
Nothing
,它将做什么

null
不是传统的“null”值-它是一个测试列表是否为空的函数。我不认为这段代码可以编译…实际上我们可以逃避
也许
@AndrewJaffe:我想他是说通过良好的旧模式匹配:
案例m的{Just x->…;Nothing->…}
必须打开Just,这正是拥有Maybe类型的关键,因为您可以让类型系统保护您免受NullPtrExceptions的影响。但关键是,某些错误有时确实最好留作错误。《前奏曲》没有
开头是有原因的::[a]->可能是一个
@AndrewJaffe我知道很多Haskeller喜欢
开头
和其他类似的东西来返回
可能
值。说得很好。在OP中,您还将看到
可能
在通过RWH时使用了更多。然后,当你回到Java或者其他什么的时候,你会很害怕,因为如果你不小心的话,你程序中的每个变量都可能变成null。