2016-12-14 15 views
1

undefinedに遭遇したときに式が失敗するはずのユニットテストをハスケルに書くのはややこしいことです。私はHSpecで次のことを試した:Haskellのレイジー式で評価された未定義のユニットテスト

module Main where 

import Test.Hspec 
import Control.Exception (evaluate) 

main :: IO() 
main = hspec $ do 
    describe "Test" $ do 
    it "test case" $ do 
     evaluate (take 1 $ map (+1) [undefined, 2, 3]) `shouldThrow` anyException 

[*** Exception: Prelude.undefined 
CallStack (from HasCallStack): 
    error, called at libraries\base\GHC\Err.hs:79:14 in base:GHC.Err 
    undefined, called at <interactive>:2:20 in interactive:Ghci1 

答えて

4

問題はevaluateはNH に自分の表現を強制したり、WHNF ないということである:それは私がREPLで同じ式を評価する場合は、私が取得したい私にdid not get expected exception: SomeException

を報告します。 GHCiでx <- evaluate (take 1 $ map (+1) [undefined, 2, 3])を試してください - それはあなたにエラーを与えることはありません! evaluate (take 1 $ map (+1) [undefined, 2, 3])に貼り付けたときの唯一の理由は、GHCiが得た結果を印刷しようとすることです。そのために、式を評価しようとします。あなたが見ることができるように、

ghci> x <- evaluate (take 1 $ map (+1) [undefined, 2, 3]) 
ghci> :sprint x 
x = [_] 

evaluatexを実現するために十分式を余儀なくされていない:

あなたが評価されているどのくらいのサンクの見たい場合は、いつでもGHCiの中:sprintを使用することができますundefinedが含まれています。簡単な修正は、forceを使用して、通常のフォームに調べているものを評価することです。

import Test.Hspec 
import Control.Exception (evaluate) 
import Control.DeepSeq (force) 

main :: IO() 
main = hspec $ do 
    describe "Test" $ do 
    it "test case" $ do 
     evaluate (force (take 1 $ map (+1) [undefined, 2, 3] :: [Int])) 
     `shouldThrow` anyException 

force引数が評価さ一杯になるまでは、サンクの評価をトリガすることができます。 NFData( "標準フォームデータ"の略)制約があることに注意してください。データ構造にはGenericNFDataが得られます。 evaluatehead $ map (+1) [undefined, 2, 3]がエラーをトリガしない理由ですWNHF、にその引数をプッシュないことを指摘し@AlexisKingため


感謝。 takeの場合は、十分ではありません。

+0

この回答は良いですが、[評価する]がWHNFに評価されないと言うと、私は混乱しています[https://hackage.haskell.org /package/base-4.9.0.0/docs/Control-Exception.html#v:evaluate)。 –

+0

@AlexisKing私は訂正しました!いずれにしても、WNHFだけでは十分ではないので、なぜNFDataが必要です。 – Alec

+0

実際には、定義されていない単一の要素を持つリストが生成されるため、テストは成功しますか?なぜ(+1)関数が適用されないのですか? –

関連する問題