当返回的对象不是字符串时,在Haskell中抛出异常。

时间:2017-10-15 03:12:13

标签: haskell exception

所以我在Haskell中编写一个程序,它收到一个数字n告诉它返回从2开始的第n个素数作为第一个素数。程序的那部分可行,但我不明白的是如何让程序在数字为0或更少时抛出异常。

pr :: Int -> Int
pr n = (filter(\x -> (getter) == []) [2..]) !! (n-1)

getter引用了我写的另一个解决主要问题的方法。它工作正常。

3 个答案:

答案 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

虽然这是默认行为,但是不完整的模式/警卫是不好的风格。相反,明确导致errorundefined

出错
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中处理它们),你应该努力寻找像MaybeEither这样的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 errorfor raisefor throw。这三个都存在 - 但raise只有不同的风格,专门针对特定的库,而throwerrorbase的一部分,因而是“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 = ...