简体   繁体   中英

Monadic if else

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?

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM