2017-10-15 41 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 = ... 
相關問題