从Haskell路到逻辑的子串练习
我最近开始阅读Keets Doets和Jan van Eijck的《Haskell通往逻辑、数学和编程之路》(非常非常好的书) 在其中一个练习中,任务是定义子字符串:我的解决方案有效 它比作者的要短得多,但我并不妄想谁是更好的逻辑学家 那么,我遗漏了什么:从Haskell路到逻辑的子串练习,haskell,Haskell,我最近开始阅读Keets Doets和Jan van Eijck的《Haskell通往逻辑、数学和编程之路》(非常非常好的书) 在其中一个练习中,任务是定义子字符串:我的解决方案有效 它比作者的要短得多,但我并不妄想谁是更好的逻辑学家 那么,我遗漏了什么: prefix :: String -> String -> Bool prefix [] y = True prefix x [] = False prefix (x:xs) (y:ys) =
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)
由于我想在一个更大的项目中亲自尝试,这对我来说是一个很好的练习。QuickCheck是一个库,它可以在生成的测试用例的属性中自动测试您的函数。您也可以创建自己的生成器,但我在这里没有这样做
首先,我使用cabalinstallquickcheck
安装了QuickCheck。我通过导入测试导入了模块。快速检查,然后定义了属性:
prop_substring xs ys = substring xs ys == substring' xs ys
如果将此属性指定给QuickCheck,则会将参数xs
和ys
生成为String
。它将检查属性是否为True
,这在本例中应该发生,因为两个子字符串
函数当然应该返回相同的结果
为了快速检查函数,我使用了verboseCheck prop\u 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.
因此,是的,这两个函数似乎提供相同的结果!尽管有两个缺点:第一个缺点是QuickCheck不太可能生成两个包含子字符串的字符串。由于它生成随机的字符串
,因此更有可能生成两个完全不同的字符串
。这可以通过创建自己的生成器来解决。第二个缺点是QuickCheck没有给你一个正式的证据
第一个可以用性质来分析。如果我们将prop_substring
更改为:
prop_substring xs ys =
collect (substring xs ys) $
(substring xs ys == substring' xs ys)
然后我们收集结果,这样我们可以看到结果的百分比。对于100000,这是:
*Substring> quickCheckWith stdArgs { maxSuccess = 100000 } prop_substring
+++ OK, passed 100000 tests:
94% False
5% True
因此,大约5000个返回值True
。您还可以生成xs
和ys
,并将参数xs
和xs++ys
或xs
和ys++xs
赋予子字符串
函数,以仅测试True
情况。这两个选项都通过了100.000次测试,因此我们几乎可以假设两个函数给出相同的结果
有关快速检查的更多信息,请参阅。例如,您可以告诉QuickCheck您需要一定数量的True
测试用例,而不是成功测试用例的总数(当两个子字符串
函数都导致False
时,也会发生成功)。您的解决方案有一个小错误,子字符串[]
是错误的。当您考虑修复时,它不会比其他解决方案短很多。他们可以使用前缀(x:xs)(y:ys)
而不是((x==y)和&(前缀xs-ys))
,这样会更好。谢谢威廉,回答得好。这真是令人愉快的脑力锻炼:)谢谢你提供的详细信息Renzeee,这就是我喜欢这个社区的原因!!我会用这个。
*Substring> quickCheckWith stdArgs { maxSuccess = 100000 } prop_substring
+++ OK, passed 100000 tests:
94% False
5% True