2017-10-15 43 views
0

所以我在Haskell中编写一个程序,它接收到一个数字n,告诉它返回从第2个素数开始的第n个素数,即第1个素数。该程序的那部分工作,但我不明白的是,如果数字为0或更少时,程序也会抛出异常。当返回的对象不是字符串时,在Haskell中抛出异常。

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

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

+0

找到您熟悉的函数的文档,然后单击Source按钮,然后查看它们的功能。一个例子就是'!!' – jberryman

+0

我没有一个我很熟悉的,因为这是我第一次使用haskell – Darkhail

+0

去体验(!!),点击[here](http://hoogle.haskell .ORG /?hoogle =(!!))。然后[这里](https://hackage.haskell.org/package/base-4.10.0.0/docs/Prelude.html#v:-33--33-)和[here](https:// hackage。 haskell.org/package/base-4.10.0.0/docs/src/GHC.List.html#%21%21)。和[这里](https://hackage.haskell.org/package/base-4.10.0.0/docs/src/GHC.List.html#negIndex)。要阅读更多关于您的主题,请尝试[this](http://learnyouahaskell.com/syntax-in-functions)并在那里搜索“警卫”。 –

回答

5

默认情况下,如果没有方程函数在给定参数匹配,你会得到一个运行时错误:

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. 

哈斯克尔也有Control.Exception更复杂的异常处理机制,但你可能不需要在这里。一般而言,例外和部分功能被忽视(因为您只能在IO中处理它们),您应该争取像MaybeEither这样的单子。

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重新定义列表的操作(包括(!!))是一元,而不是局部的。

+0

进一步的小改进:使用['null'](http://hackage.haskell.org/package/base-4.10.0.0/docs/Prelude.html#v:null)而不是'(== [])' 。更短,并且不会产生'Eq'约束:-) –

+0

@ AntalSpector-Zabusky好抓! – HTNW

0

在Haskell中,基本上所有东西都只是一个库函数。因此,它可以很容易地发现与在线搜索引擎。这包括错误处理。因此,您可能需要ask Hayoo for errorfor raisefor throw。所有这三个存在 - 但raise只在不同的口味,专门针对特定的图书馆,而throwerrorbase,因此“Haskell本身”的一部分。

  • throw可以用来生产类型正确的例外,是合适的,如果你可以在某些时候,在你的程序本身,要 /分析错误。
  • error只对崩溃的程序最有用,同时在终端上生成(希望)有用的诊断消息,这似乎是你想要的。

类型的error,如GHC-8,

error :: HasCallStack => String -> a 

HasCallStack是最近才加入,让程序告诉你其中在代码中出现错误。这不会改变您使用该功能的方式;在老版本的GHC的类型只是

error :: String -> a 

也就是说,你只要给error一些错误信息,然后用它作为任何功能,不管是什么结果类型功能的“结果”实际上应该是。在你的情况,

pr n | n >= 0  = ... 
    | otherwise = error "Table flip" 

如果你给这个函数一个负数,则它将不会给任何实际的结果,但与消息Table flip程序崩溃,并且在GHC> = 8,也告诉你,这个错误发生在pr之内。

您可能还想知道,其中pr被称为,以实际调试问题。您可以自己使用GHC调用堆栈模拟这样的:

import GHC.Stack 

pr :: HasCallStack => Int -> Int 
pr n | n >= 0  = ... 
    | otherwise = error "Table flip" 

请注意,我并不需要改变以任何方式实现,我刚添加的HasCallStack约束。


如果您在the documentation, as of GHC-8.2看,你将被示以一个相当可怕的签名

error :: forall (r :: RuntimeRep). forall (a :: TYPE r). HasCallStack => [Char] -> a 

...不要担心,这些只是实施细节提升实际上,Haskell语言并没有如此自然地支持投掷。

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 = ... 
相关问题