CS510AP Quickcheck Overview Simple Case

CS510AP Quickcheck Overview Simple Case

QuickCheck • Quick check is a Haskell library for doing random testing. CS510AP • You can read more about quickcheck at Quick Check – http://www.math.chalmers.se/~rjmh/QuickCheck/ Monads Overview Simple case • Programmers define properties they would like prop_bad xs = (reverse xs) == xs to be true about there programs where types = xs::[Int] • Programmers use default or user defined random test data generators Main> quickCheck prop_bad • The QuickCheck framework tests the properties Falsifiable, after 7 tests: against a large number of random inputs [0,4,-6,-2] • It reports the success and failure • QuickCheck is in some sense orthogonal to the kind of testing done in HUnit. A useful case Quantified tests prop_RevId xs = reverse (reverse xs) == xs <condition> ==> <property> where types = xs::[Int] Main> quickCheck prop_RevId prop_RevLong xs = OK, passed 100 tests. length xs > 2 ==> reverse (reverse xs) == xs where types = xs::[Int] Main> quickCheck prop_RevLong OK, passed 100 tests. Main> quickCheck prop_RevLong3 OK, passed 100 But Collecting data tests. 27% 3. 10% 5. prop_RevLong xs = collect <expression>$ <property> 8% 6. 6% 9. length xs > 4 ==> 5% 7. 5% 4. reverse (reverse xs) == xs prop_RevLong3 xs = 5% 10. 4% 8. where types = xs::[Int] length xs > 2 ==> 4% 16. 4% 11. collect (length xs) $ 3% 17. 3% 14. reverse (reverse xs) == xs 2% 24. Main> quickCheck prop_RevLong 2% 13. where types = xs::[Int] 2% 12. Arguments exhausted after 0 tests. 1% 44. 1% 40. 1% 36. 1% 31. 1% 28. 1% 27. 1% 26. 1% 21. 1% 18. 1% 15. A short side-trip Monads Another quantified test ordered [] = True ordered [x] = True • Monads & Actions ordered (x:y:zs) = (x <= y) && (ordered (y:zs)) • A Monad is an Abstract Data Type insert x [] = [x] (ADT) insert x (y:ys) = if x<=y then x:y:ys else y:(insert x ys) • A Monad encapsulates effects –i.e. hides their implementation prop_Insert x xs = ordered xs ==> ordered (insert x xs) • A Monad uses types to separates where types = x::Int Actions from pure computations Main> quickCheck prop_Insert • A Monad controls the order of effects OK, passed 100 tests. Actions A monad is an ADT • It is sometimes useful to use actions or side effects in a functional program . • A monad is an abstract datatype – Update a piece of state (assignment) – do some IO – draw graphics on a display –It abstracts computations with effects. – return an exception rather than an answer –It hides the details of its implementation. – generate random test cases –It exports an abstract interface. • How do we do this? –It specifies the order in which effects occur. – We use a Monad – A Monad is a type constructor which has an implied –It separates pure computations from effectfull action. ones using the type system. – For example: IO Int is an action which performs –It can have multiple implementations. some IO and then returns an Int A Monad uses types to separate Actions Monads Encapsulate Effects (with effects) from pure computations • A monad captures the meaning and use of computations which have effects on the real • A Monad is a type constructor which has an world. implied action. • A monad describes or specifies the effects in a • For example: “purely functional” way. – a computation with type (IO Int ) • A monad allows one to reason about effects, – an action which might perform some IO and which using the simple rule of substitution of equals then returns an Int for equals. • Computations with non-monadic types cannot have any effects. They are pure computations. • A monad needn’t be implemented this way The user (and the compiler) can rely on this. A monad orders effects Typing the Do If a variable is bound, it • A Monad specifies which effects come before has type a, and its scope others. is to the end of the do Each action • The Do operator provides this control over the do { var <- location x must have a order in which computations occur monadic type: ; write var (b+1) (M a) do { var <- location x -- the first action ; write var (b+1) -- the next action ; return (b+1) } } The very last action cannot have a binding A monad’s interface hides An Example: IO actions details • A monad has an interface that hides the details • Each function performs an action of doing some IO of its implementation – ? :t getChar -- get 1 char from stdin – getChar :: IO Char • Every monad has at least the two operations – ? :t putChar -- put Char to stdout – putChar :: Char -> IO() – Do Lets users control the order of actions – Return : a -> Action a makes an empty action – ? :t getLine -- get a whole line from stdin – getLine :: IO String • Each monad has its own additional operations. – ? :t readFile -- read a file into a String – readFile :: FilePath -> IO String – ? :t writeFile -- write a String to a file – writeFile :: FilePath -> String -> IO () Io operations Example: Combining IO actions getCharX :: Io Char -- get 1 char from stdin getCharX = Io(\ (c:cs) -> (c,cs,"")) getLineX :: Io [Char] getLineX = putCharX :: Char -> Io() -- put Char to stdout do { c <- getCharX -- get a char putCharX c = Io(\ s -> ((),s,[c])) ; if c == '\n' -- if its newline then return "" -- no-op action which getLineX :: Io String -- get a whole line from stdin -- returns empty string -- recursively getLineX = do { c <- getCharX else do { l <- getLine' -- get a line ; if c == '\n' ; return (c:l) -- no-op action then return "" } -- to cons c to l else do { cs <- getLineX } ; return (c:cs) } } Potentially reads a string from stdin, if it is ever performed Observations Back to Defining Generators • Actions are first class. – They can be abstracted (param’s of functions) – Stored in data structures. -- It is possible to have a list of actions, choose :: Random a => (a,a) -> Gen a etc. oneof :: [Gen a] -> Gen a • Actions can be composed. – They can be built out of smaller actions by glueing them together with do and return – They are sequenced with do much like one uses semi-colon in list:: Gen [Int] languages like Pascal and C. list = do { elem <- choose (1,100) • Actions can be performed (run). ; tail <- list – separation of construction from performance is key to their versatility. ; oneof [ return [] , return(elem:tail) ] • Actions of type: Action () are like statements in imperative languages. } – They are used only for their side effects. Note: Gen is a Monad Generating Ordered lists • Gen is a Monad orderedList:: Int -> Gen [Int] orderedList n = do { elem <- choose (1,n) • A program with type (Gen a) produces an ; tail <- orderedList elem object of type ‘a’ while performing a possible ‘Gen’ action, generating random ; oneof [ return [] bits of data. , return(elem:tail) ] } Controlling choice using Monads better frequency :: [(Int,Gen a)] -> Gen a lift :: Monad m => (b -> c) -> m b -> m c lift f x = do { a <- x; return(f a)} list2:: Gen [Int] list2 = do { elem <- choose (1,100) lift2 :: Monad m => ; tail <- list (b -> c -> d) -> m b -> m c -> m d ; frequency lift2 f x y = [ (1,return []) do { a <- x; b <- y; return(f a b)} , (4,return(elem:tail)) ] } Another list generator Generating Random RE list3:: Gen [Int] data RE list3 = = Empty frequency | Union RE RE [ (1,return []) | Concat RE RE , (4,lift2 (:) (choose (1,100)) list3) ] | Star RE | C Char Using generators re:: Gen RE forAll <generator> re = $ \<pattern> -> <property> frequency [ (1,return Empty) , (6,lift C (choose ('a','z'))) prop_re = , (3,lift2 Union re re) forAll re $ \ re -> all (reAsPred re) , (3,lift2 Concat re re) (reAsSet re) , (1,lift Star re) ] Controlling the test generation The sized function re2:: Int -> Int -> Gen RE re2 star 0 = frequency [(1,return Empty) • Test generation is controlled by the library. ,(3,lift C (choose ('a','z')))] re2 star d = • Test sizes start out small, and increase in frequency [ (3,return Empty) size as the number of tests increase. , (8,lift C (choose ('a','z'))) , (4,lift2 Union (re2 star (d-1)) (re2 star (d-1))) • Users can control this with the function , (4,lift2 Concat (re2 star (d-1)) (re2 star (d-1))) , (star,lift Star (re2 0 (d-1))) sized. ] • sized :: (Int -> Gen a) -> Gen a Using sized Installing default generators re3:: Int -> Int -> Gen RE class Arbitrary a where re3 star 0 = frequency [(1,return Empty) ,(3,lift C (choose ('a','z')))] arbitrary :: Gen a re3 star d = frequency coarbitrary :: a -> Gen b -> Gen b [ (3,return Empty) , (8,lift C (choose ('a','z'))) , (4,lift2 Union (re3 star (d `div` 2)) (re3 star (d`div` 2))) , (4,lift2 Concat (re3 star (d`div` 2)) (re3 star (d`div` 2))) , (star,lift Star (re3 0 (d`div` 2))) ] instance Arbitrary RE where prop_re3 = arbitrary = sized (re3 1) forAll (sized (re3 1)) $ \ r -> all (reAsPred r) (reAsSet r).

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    9 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us