Haskell:在异常情况下不返回任何内容
我想返回xs的第一个元素(如果有)。 否则我想返回“Nothing”,但它返回以“Just”包装的异常。 为什么呢?Haskell:在异常情况下不返回任何内容,haskell,try-catch,maybe,Haskell,Try Catch,Maybe,我想返回xs的第一个元素(如果有)。 否则我想返回“Nothing”,但它返回以“Just”包装的异常。 为什么呢? 注意:我必须在mySaveHead中使用myHead,在执行纯计算时,您可以使用evaluate捕获异常: {-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-} import Data.Typeable import Control.Exception data EmptyListException = EmptyL
注意:我必须在
mySaveHead
中使用myHead
,在执行纯计算时,您可以使用
evaluate
捕获异常:
{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}
import Data.Typeable
import Control.Exception
data EmptyListException = EmptyListException
deriving (Show, Typeable)
instance Exception EmptyListException
myHead :: [a] -> a
myHead [] = throw EmptyListException
myHead (x:_) = x
mySafeHead :: [a] -> IO (Maybe a)
mySafeHead xs = (return (Just (myHead xs)))
`catch`
(\(ex::EmptyListException) -> return Nothing)
mySafeHead::[a]->IO(可能是a)
mySafeHead xs=mySafeHead'xs`catch`handler
哪里
我的安全头“::[a]->IO(可能是a)
我的安全头'ls=do
x IO(可能是a)
handler ex=不返回任何内容
您可以使用
evaluate
在执行纯计算时捕获异常:
{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}
import Data.Typeable
import Control.Exception
data EmptyListException = EmptyListException
deriving (Show, Typeable)
instance Exception EmptyListException
myHead :: [a] -> a
myHead [] = throw EmptyListException
myHead (x:_) = x
mySafeHead :: [a] -> IO (Maybe a)
mySafeHead xs = (return (Just (myHead xs)))
`catch`
(\(ex::EmptyListException) -> return Nothing)
mySafeHead::[a]->IO(可能是a)
mySafeHead xs=mySafeHead'xs`catch`handler
哪里
我的安全头“::[a]->IO(可能是a)
我的安全头'ls=do
x IO(可能是a)
handler ex=不返回任何内容
所以当我运行你的代码时,我看到的是
mySafeHead :: [a] -> IO (Maybe a)
mySafeHead xs = mySafeHead' xs `catch` handler
where
mySafeHead' :: [a] -> IO (Maybe a)
mySafeHead' ls = do
x <- evaluate $ myHead ls
return $ Just x
handler :: EmptyListException -> IO (Maybe a)
handler ex = return Nothing
我理解为什么您会将其描述为“它返回以“Just”包装的异常”,但事实并非如此
Haskell是非严格的,所以它推迟计算,直到需要一个值
在mySafeHead
中,未检查myHead xs
的值,因此未对其进行评估。取而代之的是,该值的计算被保留为thunk,它被包装在Just
中并返回
然后,在ghci
中,当尝试打印值时,最终强制该thunk,并引发异常。因为我们现在已经远远超出了catch
语句的范围,所以它不适用,异常会一直延伸到终端,在终端中断输出的打印
解决此问题的简单方法是在退出catch
语句之前,使用seq
强制计算myHead xs
:
λ mySafeHead []
Just *** Exception: EmptyListException
seq
接受两个参数-它返回第二个参数,但仅在强制第一个参数为弱头范式(WHNF)之后,也就是说,在找出最外层的构造函数是什么之后。这就迫使x
足以引发EmptyListException
,因此catch
可以执行以下操作:
mySafeHead' :: [a] -> IO (Maybe a)
mySafeHead' xs = (let x = myHead xs in x `seq` return (Just x))
`catch`
(\(_::EmptyListException) -> return Nothing)
所以当我运行你的代码时,这就是我看到的
mySafeHead :: [a] -> IO (Maybe a)
mySafeHead xs = mySafeHead' xs `catch` handler
where
mySafeHead' :: [a] -> IO (Maybe a)
mySafeHead' ls = do
x <- evaluate $ myHead ls
return $ Just x
handler :: EmptyListException -> IO (Maybe a)
handler ex = return Nothing
我理解为什么您会将其描述为“它返回以“Just”包装的异常”,但事实并非如此
Haskell是非严格的,所以它推迟计算,直到需要一个值
在mySafeHead
中,未检查myHead xs
的值,因此未对其进行评估。取而代之的是,该值的计算被保留为thunk,它被包装在Just
中并返回
然后,在ghci
中,当尝试打印值时,最终强制该thunk,并引发异常。因为我们现在已经远远超出了catch
语句的范围,所以它不适用,异常会一直延伸到终端,在终端中断输出的打印
解决此问题的简单方法是在退出catch
语句之前,使用seq
强制计算myHead xs
:
λ mySafeHead []
Just *** Exception: EmptyListException
seq
接受两个参数-它返回第二个参数,但仅在强制第一个参数为弱头范式(WHNF)之后,也就是说,在找出最外层的构造函数是什么之后。这就迫使x
足以引发EmptyListException
,因此catch
可以执行以下操作:
mySafeHead' :: [a] -> IO (Maybe a)
mySafeHead' xs = (let x = myHead xs in x `seq` return (Just x))
`catch`
(\(_::EmptyListException) -> return Nothing)
如果您只想在 列表是非空的,否则
什么都没有
,明智的方法是
根本不使用异常(无论是由您显式抛出,还是
由于调用空列表上的head::[a]->a而引发)。相反,请定义一个总函数:
或者,从安全包装中使用
在前奏曲
中存在诸如头部
和尾部
等非全部函数是一个历史错误。希望有一天它们会被弃用,并最终被删除。如果您只想在
列表是非空的,否则什么都没有
,明智的方法是
根本不使用异常(无论是由您显式抛出,还是
由于调用空列表上的head::[a]->a而引发)。相反,请定义一个总函数:
或者,从安全包装中使用
在前奏曲
中存在诸如头部
和尾部
等非全部函数是一个历史错误。希望有一天它们会被弃用,并最终被删除。但结果的计算是不纯的(IO
monad)。@immibis捕获异常无论如何都必须在IO中。。。所以你不会真的丢失任何东西。但是结果是不纯净的(IO
monad)。@immibis捕获异常无论如何必须在IO中。。。所以你不会真的失去任何东西。这个作业很愚蠢。真正地在几乎所有情况下,在纯代码中故意抛出异常都是一个坏主意。也许这不是故意的?也许它只是对给定的东西进行建模,并且有它自己的好理由抛出异常?这个赋值是一个愚蠢的赋值。真正地在几乎所有情况下,在纯代码中故意抛出异常都是一个坏主意。也许这不是故意的?也许它只是对给定的东西进行了建模,并有自己的好理由抛出异常?奇怪,你的初始输出。愤怒的鞋子:以前从未使用过该网站,所以不知道为什么它的工作方式与我的机器不同(可能它在退出时没有刷新STDOUT,但有一点模式匹配。奇怪,你的初始输出。愤怒的鞋子:以前从未使用过那个网站,所以不确定为什么它的工作方式与我的机器不同(可能它在运行时不会刷新STDOUT)