summaryrefslogtreecommitdiff
blob: e3067a08a43dfe486a013b2544fd1a85bb8f137b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
<pkgmetadata>
	<herd>haskell</herd>
	<maintainer>
		<email>haskell@gentoo.org</email>
	</maintainer>
	<longdescription>
		Do you ever feel the need to test code involving bottoms (e.g. calls to
		the @error@ function), or code involving infinite values? Then this
		library could be useful for you.
		
		It is usually easy to get a grip on bottoms by showing a value and
		waiting to see how much gets printed before the first exception is
		encountered. However, that quickly gets tiresome and is hard to automate
		using e.g. QuickCheck
		(&lt;http://www.cse.chalmers.se/~rjmh/QuickCheck/&gt;). With this library you
		can do the tests as simply as the following examples show.
		
		Testing explicitly for bottoms:
		
		[@&gt; isBottom (head [\])@] @True@
		
		[@&gt; isBottom bottom@] @True@
		
		[@&gt; isBottom (\\_ -&gt; bottom)@] @False@
		
		[@&gt; isBottom (bottom, bottom)@] @False@
		
		Comparing finite, partial values:
		
		[@&gt; ((bottom, 3) :: (Bool, Int)) ==! (bottom, 2+5-4)@] @True@
		
		[@&gt; ((bottom, bottom) :: (Bool, Int)) &lt;! (bottom, 8)@] @True@
		
		Showing partial and infinite values (@\\\/!@ is join and @\/\\!@ is meet):
		
		[@&gt; approxShow 4 $ (True, bottom) \\\/! (bottom, \&#39;b\&#39;)@] @\&quot;Just (True, \&#39;b\&#39;)\&quot;@
		
		[@&gt; approxShow 4 $ (True, bottom) \/\\! (bottom, \&#39;b\&#39;)@] @\&quot;(_|_, _|_)\&quot;@
		
		[@&gt; approxShow 4 $ ([1..\] :: [Int\])@] @\&quot;[1, 2, 3, _\&quot;@
		
		[@&gt; approxShow 4 $ (cycle [bottom\] :: [Bool\])@] @\&quot;[_|_, _|_, _|_, _\&quot;@
		
		Approximately comparing infinite, partial values:
		
		[@&gt; approx 100 [2,4..\] ==! approx 100 (filter even [1..\] :: [Int\])@] @True@
		
		[@&gt; approx 100 [2,4..\] \/=! approx 100 (filter even [bottom..\] :: [Int\])@] @True@
		
		The code above relies on the fact that @bottom@, just as @error
		\&quot;...\&quot;@, @undefined@ and pattern match failures, yield
		exceptions. Sometimes we are dealing with properly non-terminating
		computations, such as the following example, and then it can be nice to
		be able to apply a time-out:
		
		[@&gt; timeOut&#39; 1 (reverse [1..5\])@] @Value [5,4,3,2,1]@
		
		[@&gt; timeOut&#39; 1 (reverse [1..\])@] @NonTermination@
		
		The time-out functionality can be used to treat \&quot;slow\&quot; computations as
		bottoms:
		
		[@&gt; let tweak = Tweak &amp;#x7b; approxDepth = Just 5, timeOutLimit = Just 2 &amp;#x7d;@]
		
		[@&gt; semanticEq tweak (reverse [1..\], [1..\]) (bottom :: [Int\], [1..\] :: [Int\])@] @True@
		
		[@&gt; let tweak = noTweak &amp;#x7b; timeOutLimit = Just 2 &amp;#x7d;@]
		
		[@&gt; semanticJoin tweak (reverse [1..\], True) ([\] :: [Int\], bottom)@] @Just ([],True)@
		
		This can of course be dangerous:
		
		[@&gt; let tweak = noTweak &amp;#x7b; timeOutLimit = Just 0 &amp;#x7d;@]
		
		[@&gt; semanticEq tweak (reverse [1..100000000\]) (bottom :: [Integer\])@] @True@
		
		Timeouts can also be applied to @IO@ computations:
		
		[@&gt; let primes = unfoldr (\\(x:xs) -&gt; Just (x, filter ((\/= 0) . (\`mod\` x)) xs)) [2..\]@]
		
		[@&gt; timeOutMicro 100 (print $ filter ((== 1) . (\`mod\` 83)) primes)@] @[167,499,9NonTermination@
		
		[@&gt; timeOutMicro 100 (print $ take 6 $ filter ((== 1) . (\`mod\` 83)) primes)@] @[167,499,997,1163,1993NonTermination@
		
		[@&gt; timeOutMicro 100 (print $ take 6 $ filter ((== 1) . (\`mod\` 83)) primes)@] @[167,499,997,1163,1993,2657]@
		
		[@ @] @Value ()@
		
		For the underlying theory and a larger example involving use of
		QuickCheck, see the article \&quot;Chasing Bottoms, A Case Study in Program
		Verification in the Presence of Partial and Infinite Values\&quot;
		(&lt;http://www.cse.chalmers.se/~nad/publications/danielsson-jansson-mpc2004.html&gt;).
		
		The code has been tested using GHC. Most parts can probably be
		ported to other Haskell compilers, but this would require some work.
		The @TimeOut@ functions require preemptive scheduling, and most of
		the rest requires @Data.Generics@; @isBottom@ only requires
		exceptions, though.
	</longdescription>
</pkgmetadata>