如何处理嵌套条件

时间:2014-01-07 12:16:53

标签: haskell

我正在编写一个函数,如果满足许多条件,我想返回True。例如,考虑这个比较两个字符串的函数:

test st1 st2
    | st1 == st2
        | "foo" `isInfixOf` st1 = True
        | "baz" `isInfixOf` st2 = True
        | otherwise = False
    | otherwise = False

显然,这个功能不正确。但是,我正在寻找一种测试几种条件的方法,我想知道:

A)最明智的方法是什么? B)是否有类似于我使用卫兵生成的方法?

为清楚起见,在上面的简单示例中,test的输出应如下所示:

test "foobuz" "foobuz" = True
test "foobutter" "foobuz" = False
test "buz" "buz" = False

N.B。链接条件可能是一种选择,但在经过两到三次测试后它变得非常难以理解:

test st1 st2 = st1 == st2 && "foo" `isInfixOf` s1 || "baz" `isInfixOf` s2

我在想可能有办法使用Endo Monoid来测试几个条件链?

6 个答案:

答案 0 :(得分:6)

塞巴斯蒂安对当地助手的建议很好。但是,您提供的特定示例基本上归结为if CONDITION then True else False,可以将其替换为CONDITION。所以你可以写一下:

main = print (fac 5)
test st1 st2 = st1 == st2 && ("foo" `isInfixOf` st1' || "baz" `isInfixOf` st2)

另一种写这个的方法是:

main = print (fac 5)
test st1 st2
    | st1 == st2 && "foo" `isInfixOf` st1 = True
    | st1 == st2 && "baz" `isInfixOf` st2 = True
    | otherwise                           = False

答案 1 :(得分:4)

我会使用当地帮手。

test st1 st2
    | st1 == st2 = test_after_eq st1 st2
    | otherwise = False
  where test_after_eq st1' st2'
            | "foo" `isInfixOf` st1' = True
            | "baz" `isInfixOf` st2' = True
            | otherwise = False

我认为这应该有用。

答案 2 :(得分:4)

您可以组合案例表达和模式保护:

test st1 st2 = case st1 == st2 of
    True | "foo" `isInfixOf` st1 -> ...
         | "baz" `isInfixOf` st2 -> ...
         |  otherwise            -> ...
    False -> ...

答案 3 :(得分:4)

您最接近原始代码的方式是使用MultiWayIf扩展程序:

{-# LANGUAGE MultiWayIf #-}

test st1 st2
   | st1 == st2  = ( if
      | "foo" `isInfixOf` st1 -> True
      | "baz" `isInfixOf` st2 -> True
      | otherwise             -> False )
   | otherwise                =  False

<小时/> 当然,对于这个特殊的例子,可以通过其他方式更好地完成 - 其他答案已经给出了一些建议,这里还有一个(因为你已经测试了st1==st2

test st1 st2 = st1==st2 && any (`isInfixOf`st1) ["foo", "baz"]

答案 4 :(得分:4)

虽然case在布尔值上匹配通常有点过分,但它确实为你提供了一个新的上下文。

test st1 st2 = case (st1 == st2) of
  True  | "foo" `isInfixOf` st1 -> True
        | "baz" `isInfixOf` st2 -> True
        | otherwise             -> False
  False                         -> False

您还可以使用配对形成更具异国情调的基于case的嵌套if

foo a b c = case (p1 a b, p2 b c, p3 a c) of
  (True,  _    , _   ) -> val1
  (False, False, True) -> val2
  (False, True , _   ) -> val3

答案 5 :(得分:2)

使用andor

test st1 st2 = and [ st1 == st2
                   , or ["foo" `isInfixOf` st1
                        ,"baz" `isInfixOf` st2] ]

使用AllAny幺半群:

test' st1 st2 = getAll . foldMap All $
    [ st1 == st2
    , getAny . foldMap Any $ ["foo" `isInfixOf` st1
                             ,"baz" `isInfixOf` st2]] 

来自ala的{​​{1}}函数有时可以简化newtypes的换行/解包,但这里并没有为我们节省太多:

Control.Lens.Wrapped