他人のHaskell日記 RSSフィード

Haskell初心者が、リハビリがてらに「ふつける」と「入門Haskell」片手に、試行錯誤するサイト。

2006-06-19

Prelude車輪再開発事業従事者へのQuickCheckの勧め。  Prelude車輪再開発事業従事者へのQuickCheckの勧め。 - 他人のHaskell日記 を含むブックマーク

quickCheckでsameness check

私を含めHaskellの初学者Haskellへの理解を深めるためにPrelude関数自作している人が多いように思います。

しかし、その自作した関数・・本当にPrelude関数と同じなのでしょうか?

それを確かめるためにQuickCheckが使えるのではないか、というのがこの記事の趣旨です。

やってみる

とりあえずtake関数自作してみます

take' 0 _ = []
take' n (x:xs) = x:take' (n-1) xs

これでいいかな・・実行してみよう。

*Main> take 3 [1..6]
[1,2,3]
*Main> take' 3 [1..6]
[1,2,3]
*Main> take 0 [3..8]
[]
*Main> take' 0 [3..8]
[]

よしよし動いたぞ!Prelude関数と一緒だ!

ほんとに??

ではではテスト関数(特性)を書いてみます。

QuickCheckインポートも忘れずに。

import Test.QuickCheck

take' 0 _ = []
take' n (x:xs) = x:take' (n-1) xs

prop_take :: Int -> [Int] -> Bool     --型宣言重要。型が多層型になってたら、テストデータを生成出来ない。
prop_take n xs = (take n xs == take' n xs)

さあquickCheckだ!

*Main> quickCheck prop_take
Falsifiable, after 0 tests:
-1
[-2,-1]

残念!不合格!

*Main> take (-1) [-2,-1]
[]
*Main> take' (-1) [-2,-1]
[-2,-1*** Exception: c:/cygwin/home/25.hs:(3,0)-(4,32): Non-exhaustive patterns in function take'

確かに挙動が違います。

第一引数の値が負になるケースを考えていなかったのがまずかったようです。

書き換えます!

import Test.QuickCheck

take' n _ | n <= 0 =  []                 --負の数に対応
take' n (x:xs) = x:take' (n-1) xs

prop_take :: Int -> [Int] -> Bool
prop_take n xs = (take n xs == take' n xs)

実行

*Main> take' (-1) [-2,-1]
[]

よし!じゃあ再テストだ!

*Main> quickCheck prop_take
*** Exception: c:/cygwin/home/25.hs:(3,0)-(4,32): Non-exhaustive patterns in function take'

な、何が・・

例外(Exception)が起きたときは「なにはともあれverboseCheck」が基本です。

*Main> verboseCheck prop_take
0:
-1
[]
1:
1
[2,0]
2:
1
[-1]
3:
3
[4,3,1]
4:
3
[1]
*** Exception: c:/cygwin/home/25.hs:(3,0)-(4,32): Non-exhaustive patterns in function take'

むむむ

*Main> take 3 [1]
[1]
*Main> take' 3 [1]
[1*** Exception: c:/cygwin/home/25.hs:(3,0)-(4,32): Non-exhaustive patterns in function take'

なるほど。第一引数の値が、リストのサイズより大きかったときに

空リストパターンマッチが成功せず、エラーが発生しているのですね。

パターンマッチを追加しましょう!

import Test.QuickCheck

take' n _ | n <= 0 =  []
take' n [] = []                         --追加:空リストになったらそれ以上読まない!
take' n (x:xs) = x:take' (n-1) xs

prop_take :: Int -> [Int] -> Bool
prop_take n xs = (take n xs == take' n xs)

さてどうだ?

*Main> take' 3 [1]
[1]
*Main> quickCheck prop_take
OK, passed 100 tests.

テスト合格!でけた!

 汚染は検知出来ず。

こんな風に大変便利なquickCheckですが、上に挙げた手法では問題があります。

たとえば次のコードの場合

import Test.QuickCheck

take' n _ | n <= 0 =  []
--take' n [] = []
take' n xs | length xs < n = xs        -- 変更。恐怖のアイツがいます
take' n (x:xs) = x:take' (n-1) xs

prop_take :: Int -> [Int] -> Bool
prop_take n xs = (take n xs == take' n xs)

実行してみると

*Main> quickCheck prop_take
OK, passed 100 tests.

テストに合格します。

でも実は無限リストを与えると・・

*Main> take 3 [1..]
[1,2,3]
*Main> take' 3 [1..]
GHC's heap exhausted: current limit is 268435456 bytes;
Use the `-M<size>' option to increase the total heap size.

自作関数版はlength汚染にかかっているので終了しちゃいますが、

Preludetakeの方は問題なく処理します。つまり挙動が違うわけです。

どうやらリスト型に対するデフォルトテストデータ生成機には無限リストが含まれていないようです。

テストデータ生成機を自作すれば問題無し?)

MeadowMeadow2012/01/06 03:09In the cmopliacetd world we live in, it's good to find simple solutions.

lwjtjrlwjtjr2012/01/06 19:07VCAmjP <a href="http://xzeizzjdpxdq.com/">xzeizzjdpxdq</a>

pxakzulxsiepxakzulxsie2012/01/07 23:43clkjNh , [url=http://yoqflftjklmz.com/]yoqflftjklmz[/url], [link=http://ibutncmxkxhr.com/]ibutncmxkxhr[/link], http://ckmtbknghhpf.com/

wecoawuyvwecoawuyv2012/01/08 21:30WKBmda <a href="http://cqaibwagxqav.com/">cqaibwagxqav</a>

majvaamajvaa2012/01/09 00:443mPG8V , [url=http://pefuwzkcazkn.com/]pefuwzkcazkn[/url], [link=http://zyovhdxfsoee.com/]zyovhdxfsoee[/link], http://wvnrgjpmaofa.com/

ozopebuozopebu2017/09/17 02:58http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

oujemivahebeoujemivahebe2017/09/17 03:10http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

ofubumenawofubumenaw2017/09/17 03:11http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

iranagesoliranagesol2017/09/17 03:15http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

emupugixemupugix2017/09/17 03:28http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

oefaexuvavoefaexuvav2017/09/17 03:56http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

ufuhaysevufuhaysev2017/09/17 04:09http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

enelateenelate2017/09/17 12:34http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

aqasbonawaqaqasbonawaq2017/09/17 12:47http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

coaepoecoaepoe2017/09/17 17:08http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

olaebuvaxoolaebuvaxo2017/09/17 20:20http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

ieuhopebbaieuhopebba2017/09/17 22:55http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

uminwekgaobuminwekgaob2017/09/17 23:09http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

iluoifeoxinaxiluoifeoxinax2017/09/18 01:04http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

orsozuxrnaorsozuxrna2017/09/18 02:38http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

ikuziricikuziric2017/09/18 03:02http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

uqapufudomimuqapufudomim2017/09/25 13:11http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

ojuqepeojuqepe2017/09/25 13:20http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

axikuqiaxikuqi2017/09/25 13:24http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

uviltolecajuviltolecaj2017/09/25 13:33http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

ewdemiferoewdemifero2017/09/25 13:34http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/

uhicikijeseuhicikijese2017/09/25 14:13http://20mg-levitraforsale.com/ - 20mg-levitraforsale.com.ankor <a href="http://usbuy-ventolin.com/">usbuy-ventolin.com.ankor</a> http://generic-levitracheapest-price.com/