Monadic if else

dan*_*iol 2 monads haskell

我是Haskell的新手,想要生成一Arbitrary棵树.
所以我的第一个想法是创建一个仲裁bool,如果它是真的然后返回一个空树,否则创建一个非空的树:

instance (Arbitrary a) => Arbitrary (BinaryTree a)
  arbitrary = do
    createNonEmpty <- arbitrary
    if createNonEmpty 
      then return Nil
      else generateNonEmptyTree
Run Code Online (Sandbox Code Playgroud)

但是这种创造bool的模式并且仅仅为了它而使用它似乎有点奇怪,并且感觉应该有更惯用的方式.
在我可以使用的标准库中是否已经存在某种"monadic if"

arbitrary = ifM arbitrary (return Nil) (generateNonEmptyTree)
Run Code Online (Sandbox Code Playgroud)

或者还有哪种方法可以解决这个问题呢?

Dan*_*ner 7

特别是对于QuickCheck,我会使用oneof:

arbitrary = oneof [return Nil, generateNonEmptyTree]
Run Code Online (Sandbox Code Playgroud)

它基本上是你在你的问题中提出的建议(生成一次性值,然后立即使用它):

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

但由于它是库函数,这意味着您不必在自己的代码中看到一次性值.


ram*_*ion 6

我对"使用一次绑定"的一般解决方案是-XLambdaCase:

instance (Arbitrary a) => Arbitrary (BinaryTree a)
  arbitrary = arbitrary >>= \case
    True  -> return Nil
    False -> generateNonEmptyTree
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用类似的东西

bool :: a -> a -> Bool -> a
bool f _ False = f
bool _ t True = t
Run Code Online (Sandbox Code Playgroud)

(Bool相当于eitherfoldr)

instance (Arbitrary a) => Arbitrary (BinaryTree a)
  arbitrary = bool generateNonEmptyTree (return Nil) =<< arbitrary
Run Code Online (Sandbox Code Playgroud)

  • `bool`已在`Data.Bool`中定义. (4认同)