Quickchecking with a typeclass constraint and reporting the generated values?Have you used Quickcheck in a real projectWhat's new in QuickCheck 2?Find the value that failed for quickcheckWhat is the Comonad typeclass in Haskell?Typeclass constraints on data declarationsQuickCheck: Arbitrary instances of nested data structures that generate balanced specimensHow to generate arbitrary instances of a simple type for quickcheckType Constraints in TypeclassOnly generate positive integers with QuickCheckTypeclass constraint inside typeclass instance
Scaling an object to change its key
I just entered the USA without passport control at Atlanta airport
Would a 7805 5 V regulator drain a 9 V battery?
Story of a Witch Boy
Definition of 'vrit'
What mathematical theory is required for high frequency trading?
First occurrence in the Sixers sequence
Is there a term for the belief that "if it's legal, it's moral"?
Make symbols atomic, without losing their type
reverse a call to mmap()
Implementation of the Jacobi Symbol in C
How can I restore a master database from its bak file?
How can a clan of females defend themselves in the ancient world against wandering bands?
Setting up the trap
How can I ping multiple IP addresses at the same time?
Are there any individual aliens that have gained superpowers in the Marvel universe?
Can the pre-order traversal of two different trees be the same even though they are different?
In a list with unique pairs A, B, how can I sort them so that the last B is the first A in the next pair?
Why is it 出差去 and not 去出差?
King or Queen-Which piece is which?
Why is it easier to balance a non-moving bike standing up than sitting down?
How much steel armor can you wear and still be able to swim?
How can a warlock learn from a spellbook?
I have found ports on my Samsung smart tv running a display service. What can I do with it?
Quickchecking with a typeclass constraint and reporting the generated values?
Have you used Quickcheck in a real projectWhat's new in QuickCheck 2?Find the value that failed for quickcheckWhat is the Comonad typeclass in Haskell?Typeclass constraints on data declarationsQuickCheck: Arbitrary instances of nested data structures that generate balanced specimensHow to generate arbitrary instances of a simple type for quickcheckType Constraints in TypeclassOnly generate positive integers with QuickCheckTypeclass constraint inside typeclass instance
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I'm trying to do a property-based test for a chess game. I have set up the following typeclass
class Monad m => HasCheck m where
isCollision :: Coord -> m Bool
which checks if a given coordinate contains a collision or out of bounds.
Now I have a function that generates the moveset of allowed actions for a knight like the following
collisionKnightRule :: HasCheck m => Coord -> m (Set Coord)
collisionKnightRule =
Set.filterM isCollision . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
knightMoves :: HasCheck m => Coord -> m (Set Coord)
knightMoves pos =
do let moveSet =
knightMoveSet pos
invalidMoves <- collisionKnightRule pos
return $ Set.difference moveSet invalidMoves
and an instance for the HasCheck class for an arbitrary coordinate
instance HasCheck Gen where
isCollision _ =
Quickcheck.arbitrary
and so afterwards to test this I want to ensure that the generated moveset is a proper subset of all possible moves.
knightSetProperty :: Piece.HasCheck Gen
=> (Int,Int)
-> Gen Bool
knightSetProperty position =
do moves <- Piece.knightMoves position
return $ moves `Set.isProperSubsetOf` (Piece.knightMoveSet position)
-- ... later on
it "Knight ruleset is subset" $
quickCheck knightSetProperty
Of course this fails because it could be that the knight can't move anywhere, which would mean that it's not a proper subset but the same set. However the error reported is not particularly helpful
*** Failed! Falsifiable (after 14 tests and 3 shrinks):
(0,0)
This is because quickcheck doesn't report the generated value of isCollision. Therefore I wonder, how can I make quickCheck report the generated value of isCollision
?
haskell testing typeclass quickcheck
|
show 2 more comments
I'm trying to do a property-based test for a chess game. I have set up the following typeclass
class Monad m => HasCheck m where
isCollision :: Coord -> m Bool
which checks if a given coordinate contains a collision or out of bounds.
Now I have a function that generates the moveset of allowed actions for a knight like the following
collisionKnightRule :: HasCheck m => Coord -> m (Set Coord)
collisionKnightRule =
Set.filterM isCollision . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
knightMoves :: HasCheck m => Coord -> m (Set Coord)
knightMoves pos =
do let moveSet =
knightMoveSet pos
invalidMoves <- collisionKnightRule pos
return $ Set.difference moveSet invalidMoves
and an instance for the HasCheck class for an arbitrary coordinate
instance HasCheck Gen where
isCollision _ =
Quickcheck.arbitrary
and so afterwards to test this I want to ensure that the generated moveset is a proper subset of all possible moves.
knightSetProperty :: Piece.HasCheck Gen
=> (Int,Int)
-> Gen Bool
knightSetProperty position =
do moves <- Piece.knightMoves position
return $ moves `Set.isProperSubsetOf` (Piece.knightMoveSet position)
-- ... later on
it "Knight ruleset is subset" $
quickCheck knightSetProperty
Of course this fails because it could be that the knight can't move anywhere, which would mean that it's not a proper subset but the same set. However the error reported is not particularly helpful
*** Failed! Falsifiable (after 14 tests and 3 shrinks):
(0,0)
This is because quickcheck doesn't report the generated value of isCollision. Therefore I wonder, how can I make quickCheck report the generated value of isCollision
?
haskell testing typeclass quickcheck
Why doesHasCheck
involve aMonad m
? Why do you even need that type class? Wouldn't it be simpler to have a pure functionisCollision :: Coord -> Bool
, without involving a type class?
– Mark Seemann
Mar 25 at 11:28
For the knight it's not so interesting but the pawn depends on the state of the game and if it has moved before therefore it needs to be a Monad for the State Monad.
– Marc
Mar 25 at 19:01
Could you write the function asCoord -> State s Bool
then? With an unconstrainedMonad m
,m
could also be[]
,IO
,->
,Maybe
, and all sorts of other monads. Are any of those meaningful?
– Mark Seemann
Mar 25 at 20:51
The(->)
instance of HasCheck is used for mocking in unit tests. PotentiallyIO
could be interesting too if it's instead requesting a server. The reason I implemented it that way was that I didn't want the logic for the Pieces to concern itself in anyway about how the board is implemented. In theory quickcheck shouldn't need to care about the state of the board either.
– Marc
Mar 26 at 3:35
One usually doesn't mock in FP; there's no need, because pure functions are already intrinsically testable. Could you design the code so that it's composed of pure functions instead?
– Mark Seemann
Mar 26 at 6:45
|
show 2 more comments
I'm trying to do a property-based test for a chess game. I have set up the following typeclass
class Monad m => HasCheck m where
isCollision :: Coord -> m Bool
which checks if a given coordinate contains a collision or out of bounds.
Now I have a function that generates the moveset of allowed actions for a knight like the following
collisionKnightRule :: HasCheck m => Coord -> m (Set Coord)
collisionKnightRule =
Set.filterM isCollision . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
knightMoves :: HasCheck m => Coord -> m (Set Coord)
knightMoves pos =
do let moveSet =
knightMoveSet pos
invalidMoves <- collisionKnightRule pos
return $ Set.difference moveSet invalidMoves
and an instance for the HasCheck class for an arbitrary coordinate
instance HasCheck Gen where
isCollision _ =
Quickcheck.arbitrary
and so afterwards to test this I want to ensure that the generated moveset is a proper subset of all possible moves.
knightSetProperty :: Piece.HasCheck Gen
=> (Int,Int)
-> Gen Bool
knightSetProperty position =
do moves <- Piece.knightMoves position
return $ moves `Set.isProperSubsetOf` (Piece.knightMoveSet position)
-- ... later on
it "Knight ruleset is subset" $
quickCheck knightSetProperty
Of course this fails because it could be that the knight can't move anywhere, which would mean that it's not a proper subset but the same set. However the error reported is not particularly helpful
*** Failed! Falsifiable (after 14 tests and 3 shrinks):
(0,0)
This is because quickcheck doesn't report the generated value of isCollision. Therefore I wonder, how can I make quickCheck report the generated value of isCollision
?
haskell testing typeclass quickcheck
I'm trying to do a property-based test for a chess game. I have set up the following typeclass
class Monad m => HasCheck m where
isCollision :: Coord -> m Bool
which checks if a given coordinate contains a collision or out of bounds.
Now I have a function that generates the moveset of allowed actions for a knight like the following
collisionKnightRule :: HasCheck m => Coord -> m (Set Coord)
collisionKnightRule =
Set.filterM isCollision . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
knightMoves :: HasCheck m => Coord -> m (Set Coord)
knightMoves pos =
do let moveSet =
knightMoveSet pos
invalidMoves <- collisionKnightRule pos
return $ Set.difference moveSet invalidMoves
and an instance for the HasCheck class for an arbitrary coordinate
instance HasCheck Gen where
isCollision _ =
Quickcheck.arbitrary
and so afterwards to test this I want to ensure that the generated moveset is a proper subset of all possible moves.
knightSetProperty :: Piece.HasCheck Gen
=> (Int,Int)
-> Gen Bool
knightSetProperty position =
do moves <- Piece.knightMoves position
return $ moves `Set.isProperSubsetOf` (Piece.knightMoveSet position)
-- ... later on
it "Knight ruleset is subset" $
quickCheck knightSetProperty
Of course this fails because it could be that the knight can't move anywhere, which would mean that it's not a proper subset but the same set. However the error reported is not particularly helpful
*** Failed! Falsifiable (after 14 tests and 3 shrinks):
(0,0)
This is because quickcheck doesn't report the generated value of isCollision. Therefore I wonder, how can I make quickCheck report the generated value of isCollision
?
haskell testing typeclass quickcheck
haskell testing typeclass quickcheck
asked Mar 25 at 6:05
MarcMarc
877
877
Why doesHasCheck
involve aMonad m
? Why do you even need that type class? Wouldn't it be simpler to have a pure functionisCollision :: Coord -> Bool
, without involving a type class?
– Mark Seemann
Mar 25 at 11:28
For the knight it's not so interesting but the pawn depends on the state of the game and if it has moved before therefore it needs to be a Monad for the State Monad.
– Marc
Mar 25 at 19:01
Could you write the function asCoord -> State s Bool
then? With an unconstrainedMonad m
,m
could also be[]
,IO
,->
,Maybe
, and all sorts of other monads. Are any of those meaningful?
– Mark Seemann
Mar 25 at 20:51
The(->)
instance of HasCheck is used for mocking in unit tests. PotentiallyIO
could be interesting too if it's instead requesting a server. The reason I implemented it that way was that I didn't want the logic for the Pieces to concern itself in anyway about how the board is implemented. In theory quickcheck shouldn't need to care about the state of the board either.
– Marc
Mar 26 at 3:35
One usually doesn't mock in FP; there's no need, because pure functions are already intrinsically testable. Could you design the code so that it's composed of pure functions instead?
– Mark Seemann
Mar 26 at 6:45
|
show 2 more comments
Why doesHasCheck
involve aMonad m
? Why do you even need that type class? Wouldn't it be simpler to have a pure functionisCollision :: Coord -> Bool
, without involving a type class?
– Mark Seemann
Mar 25 at 11:28
For the knight it's not so interesting but the pawn depends on the state of the game and if it has moved before therefore it needs to be a Monad for the State Monad.
– Marc
Mar 25 at 19:01
Could you write the function asCoord -> State s Bool
then? With an unconstrainedMonad m
,m
could also be[]
,IO
,->
,Maybe
, and all sorts of other monads. Are any of those meaningful?
– Mark Seemann
Mar 25 at 20:51
The(->)
instance of HasCheck is used for mocking in unit tests. PotentiallyIO
could be interesting too if it's instead requesting a server. The reason I implemented it that way was that I didn't want the logic for the Pieces to concern itself in anyway about how the board is implemented. In theory quickcheck shouldn't need to care about the state of the board either.
– Marc
Mar 26 at 3:35
One usually doesn't mock in FP; there's no need, because pure functions are already intrinsically testable. Could you design the code so that it's composed of pure functions instead?
– Mark Seemann
Mar 26 at 6:45
Why does
HasCheck
involve a Monad m
? Why do you even need that type class? Wouldn't it be simpler to have a pure function isCollision :: Coord -> Bool
, without involving a type class?– Mark Seemann
Mar 25 at 11:28
Why does
HasCheck
involve a Monad m
? Why do you even need that type class? Wouldn't it be simpler to have a pure function isCollision :: Coord -> Bool
, without involving a type class?– Mark Seemann
Mar 25 at 11:28
For the knight it's not so interesting but the pawn depends on the state of the game and if it has moved before therefore it needs to be a Monad for the State Monad.
– Marc
Mar 25 at 19:01
For the knight it's not so interesting but the pawn depends on the state of the game and if it has moved before therefore it needs to be a Monad for the State Monad.
– Marc
Mar 25 at 19:01
Could you write the function as
Coord -> State s Bool
then? With an unconstrained Monad m
, m
could also be []
, IO
, ->
, Maybe
, and all sorts of other monads. Are any of those meaningful?– Mark Seemann
Mar 25 at 20:51
Could you write the function as
Coord -> State s Bool
then? With an unconstrained Monad m
, m
could also be []
, IO
, ->
, Maybe
, and all sorts of other monads. Are any of those meaningful?– Mark Seemann
Mar 25 at 20:51
The
(->)
instance of HasCheck is used for mocking in unit tests. Potentially IO
could be interesting too if it's instead requesting a server. The reason I implemented it that way was that I didn't want the logic for the Pieces to concern itself in anyway about how the board is implemented. In theory quickcheck shouldn't need to care about the state of the board either.– Marc
Mar 26 at 3:35
The
(->)
instance of HasCheck is used for mocking in unit tests. Potentially IO
could be interesting too if it's instead requesting a server. The reason I implemented it that way was that I didn't want the logic for the Pieces to concern itself in anyway about how the board is implemented. In theory quickcheck shouldn't need to care about the state of the board either.– Marc
Mar 26 at 3:35
One usually doesn't mock in FP; there's no need, because pure functions are already intrinsically testable. Could you design the code so that it's composed of pure functions instead?
– Mark Seemann
Mar 26 at 6:45
One usually doesn't mock in FP; there's no need, because pure functions are already intrinsically testable. Could you design the code so that it's composed of pure functions instead?
– Mark Seemann
Mar 26 at 6:45
|
show 2 more comments
1 Answer
1
active
oldest
votes
Okay so I feel this should be solvable in another way. However I made the following solution that works inspired by the handler pattern.
I changed the HasCheck typeclass to a record, as follows:
data Handle = MakeHandle
isCollision :: Coord -> Bool
and then refactored all the code to use handle instead of HasCheck.
collisionKnightRule :: Handle -> Coord -> (Set Coord)
collisionKnightRule handle =
Set.filter (isCollision handle) . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
-- | Set of illegal moves
knightRuleSet :: Handle -> Coord -> (Set Coord)
knightRuleSet =
collisionKnightRule
knightMoves :: Handle -> Coord -> (Set Coord)
knightMoves handle pos =
let
moveSet =
knightMoveSet pos
invalidMoves =
knightRuleSet handle pos
in
Set.difference moveSet invalidMoves
The disadvantage of this is I fear that for stateful code it can be easy to introduce an error where you pass in a handle that is out-of-date, I.E. having multiple sources of truths. An advantage is that this is probably easier for people new to Haskell to understand. We can now mock functions using the Quickcheck's Function typeclass and pass them as an argument to make a mockHandler:
knightSetProperty ::
Fun (Int,Int) Bool
-> (Int,Int)
-> Gen Bool
knightSetProperty (Fun _ isCollision) position =
let
handler =
Piece.MakeHandle isCollision
moveSet =
Piece.knightMoves handler position
in
return $ moveSet `Set.isProperSubsetOf` (Piece.knightMoveSet position)
Now this fails properly with a counterexample:
*** Failed! Falsifiable (after 53 tests and 74 shrinks):
_->False
(0,0)
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
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
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55332047%2fquickchecking-with-a-typeclass-constraint-and-reporting-the-generated-values%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Okay so I feel this should be solvable in another way. However I made the following solution that works inspired by the handler pattern.
I changed the HasCheck typeclass to a record, as follows:
data Handle = MakeHandle
isCollision :: Coord -> Bool
and then refactored all the code to use handle instead of HasCheck.
collisionKnightRule :: Handle -> Coord -> (Set Coord)
collisionKnightRule handle =
Set.filter (isCollision handle) . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
-- | Set of illegal moves
knightRuleSet :: Handle -> Coord -> (Set Coord)
knightRuleSet =
collisionKnightRule
knightMoves :: Handle -> Coord -> (Set Coord)
knightMoves handle pos =
let
moveSet =
knightMoveSet pos
invalidMoves =
knightRuleSet handle pos
in
Set.difference moveSet invalidMoves
The disadvantage of this is I fear that for stateful code it can be easy to introduce an error where you pass in a handle that is out-of-date, I.E. having multiple sources of truths. An advantage is that this is probably easier for people new to Haskell to understand. We can now mock functions using the Quickcheck's Function typeclass and pass them as an argument to make a mockHandler:
knightSetProperty ::
Fun (Int,Int) Bool
-> (Int,Int)
-> Gen Bool
knightSetProperty (Fun _ isCollision) position =
let
handler =
Piece.MakeHandle isCollision
moveSet =
Piece.knightMoves handler position
in
return $ moveSet `Set.isProperSubsetOf` (Piece.knightMoveSet position)
Now this fails properly with a counterexample:
*** Failed! Falsifiable (after 53 tests and 74 shrinks):
_->False
(0,0)
add a comment |
Okay so I feel this should be solvable in another way. However I made the following solution that works inspired by the handler pattern.
I changed the HasCheck typeclass to a record, as follows:
data Handle = MakeHandle
isCollision :: Coord -> Bool
and then refactored all the code to use handle instead of HasCheck.
collisionKnightRule :: Handle -> Coord -> (Set Coord)
collisionKnightRule handle =
Set.filter (isCollision handle) . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
-- | Set of illegal moves
knightRuleSet :: Handle -> Coord -> (Set Coord)
knightRuleSet =
collisionKnightRule
knightMoves :: Handle -> Coord -> (Set Coord)
knightMoves handle pos =
let
moveSet =
knightMoveSet pos
invalidMoves =
knightRuleSet handle pos
in
Set.difference moveSet invalidMoves
The disadvantage of this is I fear that for stateful code it can be easy to introduce an error where you pass in a handle that is out-of-date, I.E. having multiple sources of truths. An advantage is that this is probably easier for people new to Haskell to understand. We can now mock functions using the Quickcheck's Function typeclass and pass them as an argument to make a mockHandler:
knightSetProperty ::
Fun (Int,Int) Bool
-> (Int,Int)
-> Gen Bool
knightSetProperty (Fun _ isCollision) position =
let
handler =
Piece.MakeHandle isCollision
moveSet =
Piece.knightMoves handler position
in
return $ moveSet `Set.isProperSubsetOf` (Piece.knightMoveSet position)
Now this fails properly with a counterexample:
*** Failed! Falsifiable (after 53 tests and 74 shrinks):
_->False
(0,0)
add a comment |
Okay so I feel this should be solvable in another way. However I made the following solution that works inspired by the handler pattern.
I changed the HasCheck typeclass to a record, as follows:
data Handle = MakeHandle
isCollision :: Coord -> Bool
and then refactored all the code to use handle instead of HasCheck.
collisionKnightRule :: Handle -> Coord -> (Set Coord)
collisionKnightRule handle =
Set.filter (isCollision handle) . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
-- | Set of illegal moves
knightRuleSet :: Handle -> Coord -> (Set Coord)
knightRuleSet =
collisionKnightRule
knightMoves :: Handle -> Coord -> (Set Coord)
knightMoves handle pos =
let
moveSet =
knightMoveSet pos
invalidMoves =
knightRuleSet handle pos
in
Set.difference moveSet invalidMoves
The disadvantage of this is I fear that for stateful code it can be easy to introduce an error where you pass in a handle that is out-of-date, I.E. having multiple sources of truths. An advantage is that this is probably easier for people new to Haskell to understand. We can now mock functions using the Quickcheck's Function typeclass and pass them as an argument to make a mockHandler:
knightSetProperty ::
Fun (Int,Int) Bool
-> (Int,Int)
-> Gen Bool
knightSetProperty (Fun _ isCollision) position =
let
handler =
Piece.MakeHandle isCollision
moveSet =
Piece.knightMoves handler position
in
return $ moveSet `Set.isProperSubsetOf` (Piece.knightMoveSet position)
Now this fails properly with a counterexample:
*** Failed! Falsifiable (after 53 tests and 74 shrinks):
_->False
(0,0)
Okay so I feel this should be solvable in another way. However I made the following solution that works inspired by the handler pattern.
I changed the HasCheck typeclass to a record, as follows:
data Handle = MakeHandle
isCollision :: Coord -> Bool
and then refactored all the code to use handle instead of HasCheck.
collisionKnightRule :: Handle -> Coord -> (Set Coord)
collisionKnightRule handle =
Set.filter (isCollision handle) . knightMoveSet
-- | Set of all moves, legal or not
knightMoveSet :: Coord -> Set Coord
knightMoveSet (x,y) =
Set.fromList
[ (x+2,y-1),(x+2,y+1),(x-2,y-1),(x-2,y+1)
, (x+1,y-2),(x+1,y+2),(x-1,y-2),(x-1,y+2)
]
-- | Set of illegal moves
knightRuleSet :: Handle -> Coord -> (Set Coord)
knightRuleSet =
collisionKnightRule
knightMoves :: Handle -> Coord -> (Set Coord)
knightMoves handle pos =
let
moveSet =
knightMoveSet pos
invalidMoves =
knightRuleSet handle pos
in
Set.difference moveSet invalidMoves
The disadvantage of this is I fear that for stateful code it can be easy to introduce an error where you pass in a handle that is out-of-date, I.E. having multiple sources of truths. An advantage is that this is probably easier for people new to Haskell to understand. We can now mock functions using the Quickcheck's Function typeclass and pass them as an argument to make a mockHandler:
knightSetProperty ::
Fun (Int,Int) Bool
-> (Int,Int)
-> Gen Bool
knightSetProperty (Fun _ isCollision) position =
let
handler =
Piece.MakeHandle isCollision
moveSet =
Piece.knightMoves handler position
in
return $ moveSet `Set.isProperSubsetOf` (Piece.knightMoveSet position)
Now this fails properly with a counterexample:
*** Failed! Falsifiable (after 53 tests and 74 shrinks):
_->False
(0,0)
edited Mar 27 at 9:00
answered Mar 27 at 8:50
MarcMarc
877
877
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55332047%2fquickchecking-with-a-typeclass-constraint-and-reporting-the-generated-values%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
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
Required, but never shown
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
Required, but never shown
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
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Why does
HasCheck
involve aMonad m
? Why do you even need that type class? Wouldn't it be simpler to have a pure functionisCollision :: Coord -> Bool
, without involving a type class?– Mark Seemann
Mar 25 at 11:28
For the knight it's not so interesting but the pawn depends on the state of the game and if it has moved before therefore it needs to be a Monad for the State Monad.
– Marc
Mar 25 at 19:01
Could you write the function as
Coord -> State s Bool
then? With an unconstrainedMonad m
,m
could also be[]
,IO
,->
,Maybe
, and all sorts of other monads. Are any of those meaningful?– Mark Seemann
Mar 25 at 20:51
The
(->)
instance of HasCheck is used for mocking in unit tests. PotentiallyIO
could be interesting too if it's instead requesting a server. The reason I implemented it that way was that I didn't want the logic for the Pieces to concern itself in anyway about how the board is implemented. In theory quickcheck shouldn't need to care about the state of the board either.– Marc
Mar 26 at 3:35
One usually doesn't mock in FP; there's no need, because pure functions are already intrinsically testable. Could you design the code so that it's composed of pure functions instead?
– Mark Seemann
Mar 26 at 6:45