2016-07-18 38 views
2

详尽的情况下,我有一个case表达了比较多的模式:与一元后卫

case x of 
    ... -> ... 
    ... -> ... 
    ... -> ... 
    ... -> ... 
    ... 
    _ -> ... 

其中一个案件有一个后卫:

case x of 
    ... -> ... 
    ... -> ... 
    ... | condition -> ... 
    -- If condition is false, fall through to “Rest”. 

    -- Rest: 
    ... -> ... 
    ... -> ... 
    ... 
    _ -> ... 

如果保护不匹配,我们只是通过其余的案例,没有问题。但现在我需要单点测试,所以我这样做:

case x of 
    ... -> ... 
    ... -> ... 
    ... -> do 
    condition <- action 
    if condition 
     then ... 
     else ... -- How to fall through? 

    -- Rest: 
    ... -> ... 
    ... -> ... 
    ... 
    _ -> ... 

但是,我认为我犯了一个失误。似乎没有办法让else分支继续处理其余的情况,而不复制这些分支或将它们分解为函数。无论哪种方式,都要进行详尽的检查:如果我想在警卫之后添加一个案例,编译器不知道这些匹配是否详尽无遗。

如何更改此函数或parameterise/wrap数据类型以使用monadic guard来详尽检查?

+2

我想你已经迷茫了自己。如果“Bar”匹配,则只会输入警卫(或“if-then-else”)。如果“Bar”匹配(并且达到了条件),那么您已经知道'Baz','Quux'等不匹配,因此没有理由继续使用'case'块。 –

+0

@BenjaminHodgson:很好。更新了示例。我使用一对值进行操作,并且对于后面的情况仍然可以匹配。 –

+2

不,不是。你能提供你正在使用的**实际案例,而不是一个名称,而实际上并没有显示你在做什么? – Bakuriu

回答

3

一个简单的选择是抓住case块的后半部分并将其放入单独的函数中。

case (x, y) of 
    (Foo ..., Foo ...) -> ... 
    [email protected](Bar ..., Bar ...) -> do 
    condition <- action 
    if condition 
    then ... 
    else rest x 
    x -> rest x 

rest (Baz ..., ...) = ... 
rest (Var ..., ...) = ... 
... 
rest _ = undefined 

这有点不令人满意的使用undefinedrest的落空的情况下捕捉您认为应该已经在原case块的前半部分被匹配的模式。如果你设法违反前提条件(即(Foo, Foo)等不匹配),那么你会得到一个运行时错误。

+2

如果fall-through中的匹配是相对特定的,比如'x:@ y'(@JonPurdy似乎暗示在注释中),那么可以将rest设置为两个参数函数以避免具有部分函数。 –

2

我不是下面的方法的粉丝,但我无论如何都会分享:

fix (\proceed b -> case (x, y, b) of 
    (Foo ..., Foo ..., False) -> ... 
    (Bar ..., Bar ..., False) -> do 
    condition <- action 
    if condition 
     then ... 
     else proceed True 
    (Baz ..., ..., _) -> ... 
    (Var ..., ..., _) -> ... 
    ... 
) False 

附加标志b最初是假的,所以所有的树枝都被认为。一旦我们proceed,我们将其设置为true,以便跳过第一个分支。

可能或者可能不是静态地发现详尽的,取决于实际模式。