'How does an instance of "Arbitrary" looks for a tree?
In our CS-Lectures we currently learn about QuickCheck in Haskell. Now I got a task to use QuickCheck with the following tree-type:
data Tree = Leaf Int | Node Tree Tree
deriving (Eq, Show)
I have already written some necessery equations to check different properties of trees. I know, that I need an instance of "Arbitrary" to run the whole thing. So tried this:
instance Arbitrary Tree where
arbitrary = sized tree'
where tree' 0 = do a <- arbitrary
oneof [return (Leaf a)]
tree' n = do a <- arbitrary
oneof [return (Leaf a), return (Node (tree' (n-1)) (tree' (n-1)))]
But now I am getting some errors such as:
Couldn't match type `Gen Tree' with `Tree'
Expected type: a -> Tree
Actual type: a -> Gen Tree
* In an equation for `arbitrary':
arbitrary
= sized tree'
where
tree' 0
= do a <- arbitrary
....
tree' n
= do a <- arbitrary
....
In the instance declaration for `Arbitrary Tree'
|
61 | where tree' 0 = do a <- arbitrary
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
or:
* Couldn't match type `Tree' with `Gen Tree'
Expected type: Int -> Gen Tree
Actual type: Int -> Tree
* In the first argument of `sized', namely tree'
In the expression: sized tree'
In an equation for `arbitrary':
arbitrary
= sized tree'
where
tree' 0
= do a <- arbitrary
....
tree' n
= do a <- arbitrary
....
|
60 | arbitrary = sized tree'
| ^^^^^
I think the problem is that I am doing some kind of recursion when choosing a Node. Because in that case the subtrees of that node are not trees but more like "return trees". Hopefully you know, what I mean.
Can somebody help me with this?
Thank you :)
Solution 1:[1]
The simplest way to implement this is with:
instance Arbitrary Tree where
arbitrary = frequency [
(3, Leaf <$> arbitrary)
, (1, Node <$> arbitrary <*> arbitrary)
]
Here the arbitrary
functions in bold are the ones implement for the Tree
instance. The arbitrary for Leaf
is the arbitrary
instance for an Int
.
Here we thus specify that an arbitrary tree is a leaf with an arbitrary Int
, or it is a Node
with an arbitrary left and right sub-Tree
.
or with sized :: (Int -> Gen a) -> Gen a
:
instance Arbitrary Tree where
arbitrary = sized go
where go 0 = Leaf <$> arbitrary
go n = oneof [Leaf <$> arbitrary, Node <$> go' <*> go']
where go' = go (n-1)
here the size specifies the depth of the tree, not the number of elements.
Solution 2:[2]
This can be derived using the generic-random library
{-# Language DataKinds #-}
{-# Language DeriveGeneric #-}
{-# Language DerivingVia #-}
import GHC.Generics
import Generic.Random.DerivingVia
import Test.QuickCheck
-- ghci> :set -XTypeApplications
-- ghci> sample @Tree arbitrary
-- Node (Leaf 0) (Node (Leaf 0) (Node (Leaf 0) (Node (Node (Leaf 0) (Leaf 0)) (Leaf 0))))
-- Leaf 0
-- Leaf (-2)
-- Leaf 5
-- Leaf 0
-- Leaf 2
-- Leaf 1
-- Leaf 7
-- Node (Leaf (-7)) (Leaf (-2))
-- Node (Leaf 4) (Node (Leaf 0) (Leaf 3))
-- Node (Leaf 5) (Leaf (-2))
data Tree = Leaf Int | Node Tree Tree
deriving
stock (Eq, Show, Generic)
deriving Arbitrary
via GenericArbitraryRec '[2, 1] Tree
Let me know if there is something wrong with the distribution!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Iceland_jack |
Solution 2 | Iceland_jack |