2016-07-18 72 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,以便跳過第一個分支。

可能或者可能不是靜態地發現詳盡的,取決於實際模式。