Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Haskell路到逻辑的子串练习_Haskell - Fatal编程技术网

从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) =

我最近开始阅读Keets Doets和Jan van Eijck的《Haskell通往逻辑、数学和编程之路》(非常非常好的书)

在其中一个练习中,任务是定义子字符串:我的解决方案有效 它比作者的要短得多,但我并不妄想谁是更好的逻辑学家

那么,我遗漏了什么:

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