'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 |
