9

関数が無効な値を受け取ったときにエラーをスローするようにしたいと考えています。たとえば、正の数のみを返す関数 pos があるとします。

pos :: Int -> Int
pos x
   | x >= 0 = x
   | otherwise = error "Invalid Input"

これは単純な例ですが、理解していただければ幸いです。

エラーが予想されるテスト ケースを記述し、それを合格テストと見なしたいと考えています。例えば:

tests = [pos 1 == 1, assertError pos (-1), pos 2 == 2, assertError pos (-2)]
runTests = all (== True) tests

【私の解決策】

これは、@hammarのコメントに基づいて最終的に行ったものです。

instance Eq ErrorCall where
    x == y = (show x) == (show y)

assertException :: (Exception e, Eq e) => e -> IO a -> IO ()
assertException ex action =
    handleJust isWanted (const $ return ()) $ do
        action
        assertFailure $ "Expected exception: " ++ show ex
  where isWanted = guard . (== ex) 

assertError ex f = 
    TestCase $ assertException (ErrorCall ex) $ evaluate f

tests = TestList [ (pos 0) ~?= 0
                 , (pos 1) ~?= 1
                 , assertError "Invalid Input" (pos (-1))
                 ]   

main = runTestTT tests
4

2 に答える 2

4

OPのソリューションは を定義しassertExceptionていますが、テストパックTest.HUnit.Tools.assertRaisesからもここで使用できるようです。

どのように機能するかに合わせてmsg引数を追加し、選択的なインポートを含めて、私のような初心者が一般的に使用されるものがどこからインポートされたかを知ることができるようにしました。assertErrorassertRaises

import Control.Exception (ErrorCall(ErrorCall), evaluate)
import Test.HUnit.Base  ((~?=), Test(TestCase, TestList))
import Test.HUnit.Text (runTestTT)
import Test.HUnit.Tools (assertRaises)

pos :: Int -> Int
pos x
   | x >= 0 = x
   | otherwise = error "Invalid Input"

instance Eq ErrorCall where
    x == y = (show x) == (show y)

assertError msg ex f = 
    TestCase $ assertRaises msg (ErrorCall ex) $ evaluate f

tests = TestList [
  (pos 0) ~?= 0
  , (pos 1) ~?= 1
  , assertError "Negative argument raises an error" "Invalid Input" (pos (-1))
  ]   

main = runTestTT tests
于 2013-02-10T19:49:41.137 に答える
0

Haskell でエラーを処理する方法はいくつかあります。概要は次のとおりです: http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors

[編集]

最初の例は、エラーをキャッチする方法を示しています。

half :: Int -> Int 
half x = if even x then x `div` 2 else error "odd"

main = do catch (print $ half 23) (\err -> print err)

そうは言っても、この種のエラー処理はIO、あなたのような純粋なコードでは、おそらく、どちらかまたは同様のものが通常より良い選択です。それは次のように簡単かもしれません...

pos :: Int -> Maybe Int
pos x
   | x >= 0 = Just x
   | otherwise = Nothing

tests = [pos 1 == Just 1
        ,pos (-1) == Nothing
        ,pos 2 == Just 2
        ,pos (-2) == Nothing
        ]

main = print $ and tests

...エラータイプが必要ない場合。

于 2012-11-12T19:37:43.807 に答える