所以我在Haskell中编写一个程序,它收到一个数字n告诉它返回从2开始的第n个素数作为第一个素数。程序的那部分可行,但我不明白的是如何让程序在数字为0或更少时抛出异常。
pr :: Int -> Int
pr n = (filter(\x -> (getter) == []) [2..]) !! (n-1)
getter引用了我写的另一个解决主要问题的方法。它工作正常。
答案 0 :(得分:6)
默认情况下,如果函数的方程式与给定的参数不匹配,则会出现运行时错误:
fromJust :: Maybe a -> a
fromJust (Just a) = a
-- No case for Nothing
-- fromJust Nothing throws error at runtime
但是,这对数字不起作用。相反,警卫会做类似的事情:
assertOver0 :: Int -> ()
assertOver0 n | n > 0 = ()
-- No case for n <= 0
-- assertOver0 (-1) throws error at runtime
虽然这是默认行为,但是不完整的模式/警卫是不好的风格。相反,明确导致error
或undefined
:
pr n | n >= 0 = filter (null . getter) [2..] !! n
| otherwise = error "Table flip"
-- undefined is just like error, except that error lets you give an error message
-- and undefined doesn't (undefined is more useful when you know it will never
-- be evaluated, and you don't need to give an error message)
-- undefined :: a; error :: String -> a
-- That is, they can take on any type you want them to have, because whatever code
-- is after them will never be executed anyway
-- I took liberties with your definition of pr. Your filtering function didn't use
-- x, so I wrote what I think you meant. I also made it 0-indexed.
-- Prelude.null checks for [], but doesn't incur an Eq constraint, so I replaced
-- (== []) with it.
-- Parens are not needed around the filter, because function application has
-- the highest precedence.
Haskell在Control.Exception
中也有一个更复杂的异常机制,但你可能不需要这里。一般情况下,异常和部分函数被忽略,(因为你只能在IO
中处理它们),你应该努力寻找像Maybe
或Either
这样的monad。
import Control.Monad
pr n = do guard $ n >= 0 -- guard True = Just (); guard False = Nothing (in this case)
return $ filter (null . getter) [2..] !! n
pr 2 = Just 5
pr (-1) = Nothing
但这一切都是不必要的。 (!!)
已经出现负面指数错误
ghci> "abc" !! -1
*** Exception: Prelude.!!: negative index
所以我们回到我们开始的地方:
pr n = filter (null . getter) [2..] !! n
还有a library重新定义列表操作(包括(!!)
)为monadic而不是partial。
答案 1 :(得分:0)
在Haskell中,基本上所有东西都只是一个库函数。因此,可以通过在线搜索引擎轻松找到它。这包括错误处理。因此,您可以ask Hayoo for error
,for raise
或for throw
。这三个都存在 - 但raise
只有不同的风格,专门针对特定的库,而throw
和error
是base
的一部分,因而是“Haskell本身”。
throw
可用于生成正确类型的异常,如果您可能在某个时候,在程序本身中想要捕获 /分析错误,那么它是合适的。error
对于崩溃程序非常有用,同时在终端上生成(希望)有用的诊断消息,这似乎是您想要的。 error
的类型是†,截至GHC-8,
error :: HasCallStack => String -> a
HasCallStack
是最近添加的内容,它允许程序告诉您代码中的 where 发生了错误。但这并没有改变您使用该功能的方式;在较旧版本的GHC中,类型只是
error :: String -> a
这意味着,您只需给error
一些错误消息,然后将其用作任何函数的“结果”,无论该函数的结果类型实际应该是什么是。在你的情况下,
pr n | n >= 0 = ...
| otherwise = error "Table flip"
如果你给这个函数一个负数,它就不会给出任何实际的结果,但是会使用Table flip
消息使程序崩溃,并且在GHC&gt; = 8中,也告诉你这个错误发生在{{ 1}}。
您可能还想知道其中pr
被称为,以实际调试问题。您可以自己使用GHC调用堆栈模拟:
pr
请注意,我并不需要以任何方式更改实现,我只是添加了import GHC.Stack
pr :: HasCallStack => Int -> Int
pr n | n >= 0 = ...
| otherwise = error "Table flip"
约束。
<小时/> † <子> 如果您查看the documentation, as of GHC-8.2,您将会看到一个相当可怕的签名
HasCallStack
...不要担心,这些只是实现细节引发的意思错误抛出实际上并不是Haskell语言自然支持的。
答案 2 :(得分:0)
<强>文案强> 其他答案给了你一些好的文字,所以我会在这里重复代码和解释。如果某些事情仍然不明确,那么请做评论,我会尽力填写(或者你们中的任何一位常规的S.O.回答者都可以打败我)。
答案
您提出的问题是n <= 0
的输入无效:
pr :: Int -> Int
pr n = (filter(\x -> (getter) == []) [2..]) !! (n-1)
简单的解决方案是匹配模式或警卫并手动抛出异常:
pr :: Int -> Int
pr n | n <= 0 = error "NO!"
| otherwise = ...
但有时你想要一个非字符串异常,在这种情况下你可能需要Control.Exception
:
{-# LANGUAGE DeriveAnyClass #-}
-- ^^^ This is not just a comment, enables a language extension
import Control.Exception as X
data MyException = ZeroOrNegative
deriving (Exception,Show,Eq,Ord)
-- ^^ N.B. you should derive 'Exception' for
-- types you want to 'throw'
pr n | n <= 0 = X.throw ZeroOrNegative
| otherwise = ...