QuickCheck properties for function that sorts a list of strings
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
7
down vote
favorite
I'm reading The Haskell Road to Logic, Math and Programming and for each exercise solution I write some properties to learn QuickCheck. One of the exercises is to write a function that sorts a list of strings (srtStr
). I wonder if my properties are right. Also, is there something missing?
propIdempotent â· [String] â Bool
propIdempotent xs = srtStr xs == srtStr (srtStr xs)
propLength â· [String] â Bool
propLength str = length str == length (srtStr str)
propOrder â· [String] â Bool
propOrder xs = process (srtStr xs) True where
process â· [String] â Bool â Bool
process (x : y : xs) state = process xs (if state then x <= y else False)
process _ state = state
check â· IO ()
check = do
quickCheck propIdempotent
quickCheck propLength
quickCheck propOrder
beginner haskell
add a comment |Â
up vote
7
down vote
favorite
I'm reading The Haskell Road to Logic, Math and Programming and for each exercise solution I write some properties to learn QuickCheck. One of the exercises is to write a function that sorts a list of strings (srtStr
). I wonder if my properties are right. Also, is there something missing?
propIdempotent â· [String] â Bool
propIdempotent xs = srtStr xs == srtStr (srtStr xs)
propLength â· [String] â Bool
propLength str = length str == length (srtStr str)
propOrder â· [String] â Bool
propOrder xs = process (srtStr xs) True where
process â· [String] â Bool â Bool
process (x : y : xs) state = process xs (if state then x <= y else False)
process _ state = state
check â· IO ()
check = do
quickCheck propIdempotent
quickCheck propLength
quickCheck propOrder
beginner haskell
1
Your process function should short-circuit. if you prefer you don't need to evaluateprocess xs if state is false. There are different way to achieve this.
â mb14
Apr 5 at 20:54
add a comment |Â
up vote
7
down vote
favorite
up vote
7
down vote
favorite
I'm reading The Haskell Road to Logic, Math and Programming and for each exercise solution I write some properties to learn QuickCheck. One of the exercises is to write a function that sorts a list of strings (srtStr
). I wonder if my properties are right. Also, is there something missing?
propIdempotent â· [String] â Bool
propIdempotent xs = srtStr xs == srtStr (srtStr xs)
propLength â· [String] â Bool
propLength str = length str == length (srtStr str)
propOrder â· [String] â Bool
propOrder xs = process (srtStr xs) True where
process â· [String] â Bool â Bool
process (x : y : xs) state = process xs (if state then x <= y else False)
process _ state = state
check â· IO ()
check = do
quickCheck propIdempotent
quickCheck propLength
quickCheck propOrder
beginner haskell
I'm reading The Haskell Road to Logic, Math and Programming and for each exercise solution I write some properties to learn QuickCheck. One of the exercises is to write a function that sorts a list of strings (srtStr
). I wonder if my properties are right. Also, is there something missing?
propIdempotent â· [String] â Bool
propIdempotent xs = srtStr xs == srtStr (srtStr xs)
propLength â· [String] â Bool
propLength str = length str == length (srtStr str)
propOrder â· [String] â Bool
propOrder xs = process (srtStr xs) True where
process â· [String] â Bool â Bool
process (x : y : xs) state = process xs (if state then x <= y else False)
process _ state = state
check â· IO ()
check = do
quickCheck propIdempotent
quickCheck propLength
quickCheck propOrder
beginner haskell
asked Apr 5 at 20:20
Tae
1604
1604
1
Your process function should short-circuit. if you prefer you don't need to evaluateprocess xs if state is false. There are different way to achieve this.
â mb14
Apr 5 at 20:54
add a comment |Â
1
Your process function should short-circuit. if you prefer you don't need to evaluateprocess xs if state is false. There are different way to achieve this.
â mb14
Apr 5 at 20:54
1
1
Your process function should short-circuit. if you prefer you don't need to evaluateprocess xs if state is false. There are different way to achieve this.
â mb14
Apr 5 at 20:54
Your process function should short-circuit. if you prefer you don't need to evaluateprocess xs if state is false. There are different way to achieve this.
â mb14
Apr 5 at 20:54
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
4
down vote
accepted
Correctness of a sorting algorithm consists of showing that the resulting list is in order which your propOrder
takes care of and that the resulting list is a permutation of the other list. Your propLength
does the latter partially. It prevents you from adding or removing an element out of thin air but doesn't prevent you to replace one with another.
You can write a permutation checker as follows:
First define a subbag relation that is every element of the first list appears in the second.
isSubBag :: Eq a => [ a ] -> [ a ] -> Bool
isSubBag ys = True
isSubBag (x:xs) ys = x `elem` ys && isSubBag xs (delete x ys)
Then you can write a permutation checker by applying it both ways.
isPerm :: Eq a => [ a ] -> [ a ] -> Bool
isPerm xs ys = isSubBag xs ys && isSubBag ys xs
Your property comes out as:
propPerm :: [ String ] -> Bool
propPerm xs = isPerm xs (srtStr xs)
Overall, you can improve your process function by eliminating accumulator and using the built-in conjunction. Also a better name for it would be isInOrder
process :: [String] -> Bool
process (x : y : xs) = x <= y && process (y : xs)
process _ = True
1
You can now directly check for bag equality by replacing thatTrue
withnull ys
.
â Gurkenglas
Apr 5 at 21:38
add a comment |Â
up vote
2
down vote
One property that comes to mind is that applying any permutation before srtStr
does not change the result. But what is a permutation? I'd say it's a function that doesn't exploit properties of the element type, has a left inverse and preserves the length. (The first ensures that only input elements are used. The second ensures that no elements can be dropped. The third ensures that there is no space for duplicated elements.)
propPermutationInvariant
:: (forall a. [a] -> [a]) -> (forall a. [a] -> [a]) -> [String] -> Bool
propPermutationInvariant permutation inverse xs
= length (permutation xs) /= length xs
|| inverse (permutation xs) /= xs
|| srtStr xs == srtStr (permutation xs)
For example, this implies srtStr xs == strStr (reverse xs)
, via propPermutationInvariant reverse reverse xs
.
Checking that applying a permutation before doesn't change the result isn't strong enough. For example, if the output is a singleton with the minimal element, it satisfies this property. Or a list with replicated this minimal element. But it'd be sufficient if combined with another property - that the sorting function in question is an identity on a sequence that's already sorted.
â Petr Pudlák
Apr 6 at 16:07
It's just a necessary property, not a sufficient one. The function that sorts into reverse order also satisfies this.
â Gurkenglas
Apr 7 at 14:04
add a comment |Â
up vote
1
down vote
In addition to the other great answers, I'd like to point out a few details.
First, in your process
function you skip too far, you need to go through elements one by one. Your code applied to [4, 5, 2, 3, 0, 1]
passes. Rather you need to pattern match like this:
... process (x : xs@(y : _)) state = process xs (if state then x <= y else False)
Next, as pointed out in the comment, it's better to short-circuit if the property fails. It's more efficient and also more idiomatic in Haskell. Use an accumulator only if you need it. Something like this:
prop_order :: [String] -> Bool
prop_order (x : xs@(y : _)) = (x <= y) && prop_order xs
prop_order _ = property ()
Also note that (if state then x <= y else False)
can be simplified to state && (x <= y)
.
Finally, I'd suggest you to express your property in such a way that you get more detailed information about what's wrong in a failing test. This can be accomplished using Property
instead of Bool
as the result type and using combinators in Test.QuickCheck.Property:
import Test.QuickCheck
import Test.QuickCheck.Property
-- | Tests if left is less or equal than right.
(<?=) :: (Ord a, Show a) => a -> a -> Property
x <?= y = counterexample (show x ++ " must be less than " ++ show y) (x <= y)
prop_order :: [String] -> Property
prop_order (x : xs@(y : _)) = (x <?= y) .&&. prop_order xs
prop_order _ = property ()
Note that operators (.&.) and (.&&.) are very different!
I'd probably prefer yet another variant using conjoin
, which spares you of the explicit recursion. By zipping a list with its tail we get all consecutive pairs, and then we just express that each of such pairs must satisfy <?=
.
prop_order2 :: [String] -> Property
prop_order2 xs = conjoin $ zipWith (<?=) xs (tail xs)
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
Correctness of a sorting algorithm consists of showing that the resulting list is in order which your propOrder
takes care of and that the resulting list is a permutation of the other list. Your propLength
does the latter partially. It prevents you from adding or removing an element out of thin air but doesn't prevent you to replace one with another.
You can write a permutation checker as follows:
First define a subbag relation that is every element of the first list appears in the second.
isSubBag :: Eq a => [ a ] -> [ a ] -> Bool
isSubBag ys = True
isSubBag (x:xs) ys = x `elem` ys && isSubBag xs (delete x ys)
Then you can write a permutation checker by applying it both ways.
isPerm :: Eq a => [ a ] -> [ a ] -> Bool
isPerm xs ys = isSubBag xs ys && isSubBag ys xs
Your property comes out as:
propPerm :: [ String ] -> Bool
propPerm xs = isPerm xs (srtStr xs)
Overall, you can improve your process function by eliminating accumulator and using the built-in conjunction. Also a better name for it would be isInOrder
process :: [String] -> Bool
process (x : y : xs) = x <= y && process (y : xs)
process _ = True
1
You can now directly check for bag equality by replacing thatTrue
withnull ys
.
â Gurkenglas
Apr 5 at 21:38
add a comment |Â
up vote
4
down vote
accepted
Correctness of a sorting algorithm consists of showing that the resulting list is in order which your propOrder
takes care of and that the resulting list is a permutation of the other list. Your propLength
does the latter partially. It prevents you from adding or removing an element out of thin air but doesn't prevent you to replace one with another.
You can write a permutation checker as follows:
First define a subbag relation that is every element of the first list appears in the second.
isSubBag :: Eq a => [ a ] -> [ a ] -> Bool
isSubBag ys = True
isSubBag (x:xs) ys = x `elem` ys && isSubBag xs (delete x ys)
Then you can write a permutation checker by applying it both ways.
isPerm :: Eq a => [ a ] -> [ a ] -> Bool
isPerm xs ys = isSubBag xs ys && isSubBag ys xs
Your property comes out as:
propPerm :: [ String ] -> Bool
propPerm xs = isPerm xs (srtStr xs)
Overall, you can improve your process function by eliminating accumulator and using the built-in conjunction. Also a better name for it would be isInOrder
process :: [String] -> Bool
process (x : y : xs) = x <= y && process (y : xs)
process _ = True
1
You can now directly check for bag equality by replacing thatTrue
withnull ys
.
â Gurkenglas
Apr 5 at 21:38
add a comment |Â
up vote
4
down vote
accepted
up vote
4
down vote
accepted
Correctness of a sorting algorithm consists of showing that the resulting list is in order which your propOrder
takes care of and that the resulting list is a permutation of the other list. Your propLength
does the latter partially. It prevents you from adding or removing an element out of thin air but doesn't prevent you to replace one with another.
You can write a permutation checker as follows:
First define a subbag relation that is every element of the first list appears in the second.
isSubBag :: Eq a => [ a ] -> [ a ] -> Bool
isSubBag ys = True
isSubBag (x:xs) ys = x `elem` ys && isSubBag xs (delete x ys)
Then you can write a permutation checker by applying it both ways.
isPerm :: Eq a => [ a ] -> [ a ] -> Bool
isPerm xs ys = isSubBag xs ys && isSubBag ys xs
Your property comes out as:
propPerm :: [ String ] -> Bool
propPerm xs = isPerm xs (srtStr xs)
Overall, you can improve your process function by eliminating accumulator and using the built-in conjunction. Also a better name for it would be isInOrder
process :: [String] -> Bool
process (x : y : xs) = x <= y && process (y : xs)
process _ = True
Correctness of a sorting algorithm consists of showing that the resulting list is in order which your propOrder
takes care of and that the resulting list is a permutation of the other list. Your propLength
does the latter partially. It prevents you from adding or removing an element out of thin air but doesn't prevent you to replace one with another.
You can write a permutation checker as follows:
First define a subbag relation that is every element of the first list appears in the second.
isSubBag :: Eq a => [ a ] -> [ a ] -> Bool
isSubBag ys = True
isSubBag (x:xs) ys = x `elem` ys && isSubBag xs (delete x ys)
Then you can write a permutation checker by applying it both ways.
isPerm :: Eq a => [ a ] -> [ a ] -> Bool
isPerm xs ys = isSubBag xs ys && isSubBag ys xs
Your property comes out as:
propPerm :: [ String ] -> Bool
propPerm xs = isPerm xs (srtStr xs)
Overall, you can improve your process function by eliminating accumulator and using the built-in conjunction. Also a better name for it would be isInOrder
process :: [String] -> Bool
process (x : y : xs) = x <= y && process (y : xs)
process _ = True
edited Apr 5 at 21:30
answered Apr 5 at 20:52
Madgen
562
562
1
You can now directly check for bag equality by replacing thatTrue
withnull ys
.
â Gurkenglas
Apr 5 at 21:38
add a comment |Â
1
You can now directly check for bag equality by replacing thatTrue
withnull ys
.
â Gurkenglas
Apr 5 at 21:38
1
1
You can now directly check for bag equality by replacing that
True
with null ys
.â Gurkenglas
Apr 5 at 21:38
You can now directly check for bag equality by replacing that
True
with null ys
.â Gurkenglas
Apr 5 at 21:38
add a comment |Â
up vote
2
down vote
One property that comes to mind is that applying any permutation before srtStr
does not change the result. But what is a permutation? I'd say it's a function that doesn't exploit properties of the element type, has a left inverse and preserves the length. (The first ensures that only input elements are used. The second ensures that no elements can be dropped. The third ensures that there is no space for duplicated elements.)
propPermutationInvariant
:: (forall a. [a] -> [a]) -> (forall a. [a] -> [a]) -> [String] -> Bool
propPermutationInvariant permutation inverse xs
= length (permutation xs) /= length xs
|| inverse (permutation xs) /= xs
|| srtStr xs == srtStr (permutation xs)
For example, this implies srtStr xs == strStr (reverse xs)
, via propPermutationInvariant reverse reverse xs
.
Checking that applying a permutation before doesn't change the result isn't strong enough. For example, if the output is a singleton with the minimal element, it satisfies this property. Or a list with replicated this minimal element. But it'd be sufficient if combined with another property - that the sorting function in question is an identity on a sequence that's already sorted.
â Petr Pudlák
Apr 6 at 16:07
It's just a necessary property, not a sufficient one. The function that sorts into reverse order also satisfies this.
â Gurkenglas
Apr 7 at 14:04
add a comment |Â
up vote
2
down vote
One property that comes to mind is that applying any permutation before srtStr
does not change the result. But what is a permutation? I'd say it's a function that doesn't exploit properties of the element type, has a left inverse and preserves the length. (The first ensures that only input elements are used. The second ensures that no elements can be dropped. The third ensures that there is no space for duplicated elements.)
propPermutationInvariant
:: (forall a. [a] -> [a]) -> (forall a. [a] -> [a]) -> [String] -> Bool
propPermutationInvariant permutation inverse xs
= length (permutation xs) /= length xs
|| inverse (permutation xs) /= xs
|| srtStr xs == srtStr (permutation xs)
For example, this implies srtStr xs == strStr (reverse xs)
, via propPermutationInvariant reverse reverse xs
.
Checking that applying a permutation before doesn't change the result isn't strong enough. For example, if the output is a singleton with the minimal element, it satisfies this property. Or a list with replicated this minimal element. But it'd be sufficient if combined with another property - that the sorting function in question is an identity on a sequence that's already sorted.
â Petr Pudlák
Apr 6 at 16:07
It's just a necessary property, not a sufficient one. The function that sorts into reverse order also satisfies this.
â Gurkenglas
Apr 7 at 14:04
add a comment |Â
up vote
2
down vote
up vote
2
down vote
One property that comes to mind is that applying any permutation before srtStr
does not change the result. But what is a permutation? I'd say it's a function that doesn't exploit properties of the element type, has a left inverse and preserves the length. (The first ensures that only input elements are used. The second ensures that no elements can be dropped. The third ensures that there is no space for duplicated elements.)
propPermutationInvariant
:: (forall a. [a] -> [a]) -> (forall a. [a] -> [a]) -> [String] -> Bool
propPermutationInvariant permutation inverse xs
= length (permutation xs) /= length xs
|| inverse (permutation xs) /= xs
|| srtStr xs == srtStr (permutation xs)
For example, this implies srtStr xs == strStr (reverse xs)
, via propPermutationInvariant reverse reverse xs
.
One property that comes to mind is that applying any permutation before srtStr
does not change the result. But what is a permutation? I'd say it's a function that doesn't exploit properties of the element type, has a left inverse and preserves the length. (The first ensures that only input elements are used. The second ensures that no elements can be dropped. The third ensures that there is no space for duplicated elements.)
propPermutationInvariant
:: (forall a. [a] -> [a]) -> (forall a. [a] -> [a]) -> [String] -> Bool
propPermutationInvariant permutation inverse xs
= length (permutation xs) /= length xs
|| inverse (permutation xs) /= xs
|| srtStr xs == srtStr (permutation xs)
For example, this implies srtStr xs == strStr (reverse xs)
, via propPermutationInvariant reverse reverse xs
.
edited Apr 5 at 21:08
answered Apr 5 at 21:01
Gurkenglas
2,658411
2,658411
Checking that applying a permutation before doesn't change the result isn't strong enough. For example, if the output is a singleton with the minimal element, it satisfies this property. Or a list with replicated this minimal element. But it'd be sufficient if combined with another property - that the sorting function in question is an identity on a sequence that's already sorted.
â Petr Pudlák
Apr 6 at 16:07
It's just a necessary property, not a sufficient one. The function that sorts into reverse order also satisfies this.
â Gurkenglas
Apr 7 at 14:04
add a comment |Â
Checking that applying a permutation before doesn't change the result isn't strong enough. For example, if the output is a singleton with the minimal element, it satisfies this property. Or a list with replicated this minimal element. But it'd be sufficient if combined with another property - that the sorting function in question is an identity on a sequence that's already sorted.
â Petr Pudlák
Apr 6 at 16:07
It's just a necessary property, not a sufficient one. The function that sorts into reverse order also satisfies this.
â Gurkenglas
Apr 7 at 14:04
Checking that applying a permutation before doesn't change the result isn't strong enough. For example, if the output is a singleton with the minimal element, it satisfies this property. Or a list with replicated this minimal element. But it'd be sufficient if combined with another property - that the sorting function in question is an identity on a sequence that's already sorted.
â Petr Pudlák
Apr 6 at 16:07
Checking that applying a permutation before doesn't change the result isn't strong enough. For example, if the output is a singleton with the minimal element, it satisfies this property. Or a list with replicated this minimal element. But it'd be sufficient if combined with another property - that the sorting function in question is an identity on a sequence that's already sorted.
â Petr Pudlák
Apr 6 at 16:07
It's just a necessary property, not a sufficient one. The function that sorts into reverse order also satisfies this.
â Gurkenglas
Apr 7 at 14:04
It's just a necessary property, not a sufficient one. The function that sorts into reverse order also satisfies this.
â Gurkenglas
Apr 7 at 14:04
add a comment |Â
up vote
1
down vote
In addition to the other great answers, I'd like to point out a few details.
First, in your process
function you skip too far, you need to go through elements one by one. Your code applied to [4, 5, 2, 3, 0, 1]
passes. Rather you need to pattern match like this:
... process (x : xs@(y : _)) state = process xs (if state then x <= y else False)
Next, as pointed out in the comment, it's better to short-circuit if the property fails. It's more efficient and also more idiomatic in Haskell. Use an accumulator only if you need it. Something like this:
prop_order :: [String] -> Bool
prop_order (x : xs@(y : _)) = (x <= y) && prop_order xs
prop_order _ = property ()
Also note that (if state then x <= y else False)
can be simplified to state && (x <= y)
.
Finally, I'd suggest you to express your property in such a way that you get more detailed information about what's wrong in a failing test. This can be accomplished using Property
instead of Bool
as the result type and using combinators in Test.QuickCheck.Property:
import Test.QuickCheck
import Test.QuickCheck.Property
-- | Tests if left is less or equal than right.
(<?=) :: (Ord a, Show a) => a -> a -> Property
x <?= y = counterexample (show x ++ " must be less than " ++ show y) (x <= y)
prop_order :: [String] -> Property
prop_order (x : xs@(y : _)) = (x <?= y) .&&. prop_order xs
prop_order _ = property ()
Note that operators (.&.) and (.&&.) are very different!
I'd probably prefer yet another variant using conjoin
, which spares you of the explicit recursion. By zipping a list with its tail we get all consecutive pairs, and then we just express that each of such pairs must satisfy <?=
.
prop_order2 :: [String] -> Property
prop_order2 xs = conjoin $ zipWith (<?=) xs (tail xs)
add a comment |Â
up vote
1
down vote
In addition to the other great answers, I'd like to point out a few details.
First, in your process
function you skip too far, you need to go through elements one by one. Your code applied to [4, 5, 2, 3, 0, 1]
passes. Rather you need to pattern match like this:
... process (x : xs@(y : _)) state = process xs (if state then x <= y else False)
Next, as pointed out in the comment, it's better to short-circuit if the property fails. It's more efficient and also more idiomatic in Haskell. Use an accumulator only if you need it. Something like this:
prop_order :: [String] -> Bool
prop_order (x : xs@(y : _)) = (x <= y) && prop_order xs
prop_order _ = property ()
Also note that (if state then x <= y else False)
can be simplified to state && (x <= y)
.
Finally, I'd suggest you to express your property in such a way that you get more detailed information about what's wrong in a failing test. This can be accomplished using Property
instead of Bool
as the result type and using combinators in Test.QuickCheck.Property:
import Test.QuickCheck
import Test.QuickCheck.Property
-- | Tests if left is less or equal than right.
(<?=) :: (Ord a, Show a) => a -> a -> Property
x <?= y = counterexample (show x ++ " must be less than " ++ show y) (x <= y)
prop_order :: [String] -> Property
prop_order (x : xs@(y : _)) = (x <?= y) .&&. prop_order xs
prop_order _ = property ()
Note that operators (.&.) and (.&&.) are very different!
I'd probably prefer yet another variant using conjoin
, which spares you of the explicit recursion. By zipping a list with its tail we get all consecutive pairs, and then we just express that each of such pairs must satisfy <?=
.
prop_order2 :: [String] -> Property
prop_order2 xs = conjoin $ zipWith (<?=) xs (tail xs)
add a comment |Â
up vote
1
down vote
up vote
1
down vote
In addition to the other great answers, I'd like to point out a few details.
First, in your process
function you skip too far, you need to go through elements one by one. Your code applied to [4, 5, 2, 3, 0, 1]
passes. Rather you need to pattern match like this:
... process (x : xs@(y : _)) state = process xs (if state then x <= y else False)
Next, as pointed out in the comment, it's better to short-circuit if the property fails. It's more efficient and also more idiomatic in Haskell. Use an accumulator only if you need it. Something like this:
prop_order :: [String] -> Bool
prop_order (x : xs@(y : _)) = (x <= y) && prop_order xs
prop_order _ = property ()
Also note that (if state then x <= y else False)
can be simplified to state && (x <= y)
.
Finally, I'd suggest you to express your property in such a way that you get more detailed information about what's wrong in a failing test. This can be accomplished using Property
instead of Bool
as the result type and using combinators in Test.QuickCheck.Property:
import Test.QuickCheck
import Test.QuickCheck.Property
-- | Tests if left is less or equal than right.
(<?=) :: (Ord a, Show a) => a -> a -> Property
x <?= y = counterexample (show x ++ " must be less than " ++ show y) (x <= y)
prop_order :: [String] -> Property
prop_order (x : xs@(y : _)) = (x <?= y) .&&. prop_order xs
prop_order _ = property ()
Note that operators (.&.) and (.&&.) are very different!
I'd probably prefer yet another variant using conjoin
, which spares you of the explicit recursion. By zipping a list with its tail we get all consecutive pairs, and then we just express that each of such pairs must satisfy <?=
.
prop_order2 :: [String] -> Property
prop_order2 xs = conjoin $ zipWith (<?=) xs (tail xs)
In addition to the other great answers, I'd like to point out a few details.
First, in your process
function you skip too far, you need to go through elements one by one. Your code applied to [4, 5, 2, 3, 0, 1]
passes. Rather you need to pattern match like this:
... process (x : xs@(y : _)) state = process xs (if state then x <= y else False)
Next, as pointed out in the comment, it's better to short-circuit if the property fails. It's more efficient and also more idiomatic in Haskell. Use an accumulator only if you need it. Something like this:
prop_order :: [String] -> Bool
prop_order (x : xs@(y : _)) = (x <= y) && prop_order xs
prop_order _ = property ()
Also note that (if state then x <= y else False)
can be simplified to state && (x <= y)
.
Finally, I'd suggest you to express your property in such a way that you get more detailed information about what's wrong in a failing test. This can be accomplished using Property
instead of Bool
as the result type and using combinators in Test.QuickCheck.Property:
import Test.QuickCheck
import Test.QuickCheck.Property
-- | Tests if left is less or equal than right.
(<?=) :: (Ord a, Show a) => a -> a -> Property
x <?= y = counterexample (show x ++ " must be less than " ++ show y) (x <= y)
prop_order :: [String] -> Property
prop_order (x : xs@(y : _)) = (x <?= y) .&&. prop_order xs
prop_order _ = property ()
Note that operators (.&.) and (.&&.) are very different!
I'd probably prefer yet another variant using conjoin
, which spares you of the explicit recursion. By zipping a list with its tail we get all consecutive pairs, and then we just express that each of such pairs must satisfy <?=
.
prop_order2 :: [String] -> Property
prop_order2 xs = conjoin $ zipWith (<?=) xs (tail xs)
answered Apr 8 at 9:48
Petr Pudlák
2,755931
2,755931
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191353%2fquickcheck-properties-for-function-that-sorts-a-list-of-strings%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
Your process function should short-circuit. if you prefer you don't need to evaluateprocess xs if state is false. There are different way to achieve this.
â mb14
Apr 5 at 20:54