我最近开始通过Keets Doets的书“Haskell通向逻辑,数学和编程之路”这本书开始工作。 Jan van Eijck(非常好的书)。
在其中一个练习中,任务是定义子字符串:我的解决方案有效 并且比作者的短得多,但是我并不妄想谁是更好的逻辑师。
那么,我错过了什么:
prefix :: String -> String -> Bool
prefix [] y = True
prefix x [] = False
prefix (x:xs) (y:ys) = (x == y) && (prefix xs ys)
substring :: String -> String -> Bool
substring x [] = False
substring x (y:ys) | prefix x (y:ys) = True
| otherwise = substring x ys
-- Thought the answer provided was a bit overdone
substring' :: String -> String -> Bool
substring' [] ys = True
substring' (x:xs) [] = False
substring' (x:xs) (y:ys) = ((x==y) && (prefix xs ys)) || (substring' (x:xs) ys)
亲切的问候Auke
答案 0 :(得分:3)
由于我想在一个更大的项目中为自己尝试QuickCheck ,这对我来说是一个很好的练习。 QuickCheck是一个库,可以在生成的测试用例的属性中自动测试您的函数。你也可以创建自己的发电机,但我没有在这里做。
首先,我使用cabal install QuickCheck
安装了QuickCheck。我通过import Test.QuickCheck
导入了模块,然后我定义了属性:
prop_substring xs ys = substring xs ys == substring' xs ys
此属性(如果提供给QuickCheck)将生成xs
和ys
作为String
的参数。它将检查属性是否为True
,在这种情况下应该发生,因为substring
函数当然应该返回相同的结果。
要快速查看该功能,我使用了verboseCheck prop_substring
。这将检查100个生成的测试用例。第一个结果是:
Failed:
""
""
*** Failed! Falsifiable (after 1 test):
""
""
所以:不,这两个功能不一样。这是因为在你的函数substring
中,如果第一个参数为空,则不测试它是子字符串的基本情况,所以我添加了一行:
substring [] ys = True
然后,我再次测试了它。以下是最后两个生成的测试用例示例:
Passed:
"C8Q<r6\195@\v_\195\DC1\170"
"E\219\DLE"
Passed:
"$ I\SYN\232\164\EOT9\182Ldah\255\173\DC2-B\DC2\SUBuF|\235iQ\236l\vS129\237x?}\187\229C\SYNUVUc/3bO7mE\ESCHB7V\DEL\FSM\EM\202^\162!\GS\DC3\\\nja\201\ESC\ENQOi"
"&?\USx>{\147\DC4g\171\EM\240Ha%\"C\ETX \SI\FS=\DC2\214V%H"
+++ OK, passed 100 tests.
但这只是100次测试,还有更多?您可以使用其他函数并使用其他参数。让我们尝试使用100.000个测试用例:
*Substring> quickCheckWith stdArgs { maxSuccess = 100000 } prop_substring
+++ OK, passed 100000 tests.
所以是的,似乎两个功能都能提供相同的结果!虽然有两个不足之处:第一个是QuickCheck不太可能生成两个带有substring
的字符串。当它生成随机String
时,它更有可能生成两个完全不同的String
。这可以通过创建自己的生成器来解决。第二个缺点是QuickCheck没有给你一个正式的证据。
可以使用属性分析第一个。如果我们将prop_substring
更改为:
prop_substring xs ys =
collect (substring xs ys) $
(substring xs ys == substring' xs ys)
然后我们收集结果,因此我们可以看到结果的百分比。对于100.000,这是:
*Substring> quickCheckWith stdArgs { maxSuccess = 100000 } prop_substring
+++ OK, passed 100000 tests:
94% False
5% True
所以,大约5000返回True
。您还可以生成xs
和ys
,并为substring
- 函数提供参数xs
和xs++ys
或xs
和ys++xs
仅测试True
个案例。两个选项都通过了100.000次测试,所以我们几乎可以假设两个函数都给出了相同的结果。
有关QuickCheck的更多信息有点outdated manual。例如,您可以告诉QuickCheck您需要一定数量的True
个测试用例,而不是成功测试用例的总数(当substring
个函数都导致False
时,也会成功)。