4

I am new to Haskell and want to generate an Arbitrary tree.
So my first idea is to create an arbitary bool, if it is true then return an empty tree and else create a non-empty one:

instance (Arbitrary a) => Arbitrary (BinaryTree a) arbitrary = do createNonEmpty <- arbitrary if createNonEmpty then return Nil else generateNonEmptyTree 

But this pattern of creating the bool and use it just for that if seems a bit odd and it feels like there should be a more idiomatic way.
Is there already some kind of "monadic if" in the standard library that I could use like

arbitrary = ifM arbitrary (return Nil) (generateNonEmptyTree) 

Or what else is the most idiomatic way to solve this?

8
  • 2
    ifM is indeed a very popular idea that exists in a number of "general-purpose" libraries, check out Stackage. Commented Mar 29, 2018 at 20:04
  • If I understand correctly these are non standard libraries? Commented Mar 29, 2018 at 20:16
  • Unlike .NET or Java or other similar ecosystems, most Haskell libraries are "non-standard". The only "standard" one would probably be Prelude. To some degree of approximation, one could consider Stack to be the Haskell "standard", and in that sense all those libraries are, in fact, "standard", since they're included in the Stack snapshot. Commented Mar 29, 2018 at 20:24
  • 3
    @ThomasCook No, he means Arbitrary from the non-standard QuickCheck I believe. Commented Mar 29, 2018 at 20:26
  • 1
    @FyodorSoikin (1) "Unlike .NET or Java or other similar ecosystems, most Haskell libraries are 'non-standard'" -- Indeed; standard versus non-standard libs isn't really relevant in Haskell practice. (2) "To some degree of approximation, one could consider Stack to be the Haskell 'standard', and in that sense all those libraries are, in fact, 'standard'" -- Even with the caveats, I feel this is too much of a stretch. Stackage is, by design, too large and uncohesive to be seen in that way; also, the adoption of it (and Stack) isn't sufficiently close to universal. Commented Mar 30, 2018 at 1:39

2 Answers 2

7

For QuickCheck in particular, I'd use oneof:

arbitrary = oneof [return Nil, generateNonEmptyTree] 

It does essentially what you propose in your question (generate a one-off value, then use it immediately):

oneof :: [Gen a] -> Gen a oneof [] = error "QuickCheck.oneof used with empty list" oneof gs = choose (0,length gs - 1) >>= (gs !!) 

But since it's a library function, this means you don't have to see the one-off values in your own code.

Sign up to request clarification or add additional context in comments.

Comments

6

My general solution to the "use once binding" is -XLambdaCase:

instance (Arbitrary a) => Arbitrary (BinaryTree a) arbitrary = arbitrary >>= \case True -> return Nil False -> generateNonEmptyTree 

Alternately, you could use something like

bool :: a -> a -> Bool -> a bool f _ False = f bool _ t True = t 

(Bool's equivalent to either or foldr)

instance (Arbitrary a) => Arbitrary (BinaryTree a) arbitrary = bool generateNonEmptyTree (return Nil) =<< arbitrary 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.