3
// Standard pattern matching. 
let Foo x = 
    match x with 
    | 1 -> 
     // ... lots of code, only evaluated if x == 1 
    | 2 -> 
     // ... lots of code, only evaluated if x == 2 

// Standard pattern matching separated out, causing exception. 
let Bar x = 
    let valueOne = //... lots of code, evaluated always. Exception if value <> 1. 
    let valueTwo = //... lots of code, evaluated always. Exception if value <> 2. 

    match x with 
    | 1 -> valueOne 
    | 2 -> valueTwo 

匹配在使用「匹配」,對於每個圖案的代碼可以是大的圖案匹配,見上面,讓我想打出塊作爲分開呼叫以提高可讀性。分裂流出塊是爲了便於閱讀

與此相關的問題可能是,即使圖案不匹配,也會評估呼叫,如上面的Bar

  • 選項1:懶惰評估。
  • 選項2:轉發參數/參數。
  • 選項3:轉發參數/參數並使用活動模式。

什麼是提高可讀性的首選方法,其中每個模式下的代碼可能很大。或者還有其他明顯的解決方案嗎?

// ===== OPTION 1 ===== 
// Pattern matching separated out, lazy eval. 
let Foo x = 
    let valueOne = lazy //... lots of code, evaluated on Force(). 
    let valueTwo = lazy //... lots of code, evaluated on Force(). 

    match x with 
    | 1 -> valueOne.Force() 
    | 2 -> valueTwo.Force() 

// ===== OPTION 2 ===== 
// Pattern matching separated out, with arguments. 
let Foo x = 
    let valueOne a = //... lots of code. 
    let valueTwo a = //... lots of code. 

    match x with 
    | 1 -> valueOne x 
    | 2 -> valueTwo x 

// ===== OPTION 3 ===== 
// Active Pattern matching separated out, with arguments. 
let Foo x = 
    let (|ValueOne|_|) inp = 
    if inp = 1 then Some(...) else None 

    let (|ValueTwo|_|) inp = 
    if inp = 2 then Some(...) else None 

    match x with 
    | ValueOne a -> a 
    | ValueTwo b -> b 
+0

我會使用一個活動模式,如果命名明智,他們很擅長解決這種類型的問題。 – s952163

+1

假設不同的案例應該有不同的代碼,我只會使用函數而不是數值或'懶惰'。如果使用相同的代碼,則可以使用「活動模式」將不同情況合併爲單個匹配 – FuleSnabel

回答

6

我可能只是提取模式的兩個機構匹配成採取unit功能:

let caseOne() = 
    // Lots of code when x=1 

let caseTwo() = 
    // Lots of code when x=2 

let Foo x = 
    match x with 
    | 1 -> caseOne() 
    | 2 -> caseTwo() 

這類似於使用lazy您的解決方案,但我們從來沒有被重新使用的結果懶惰的價值,真的沒有理由使用懶惰值 - 一個函數更簡單,它也延遲了對正文的評價。

如果您發現caseOnecaseTwo之間存在一些共性,您可以再次將其提取到另一個函數中,這兩個函數都可以調用它們。

4

一般來說,我嘗試讓我的代碼的語義匹配我試圖完成的邏輯。在你的情況下,我會形容你的問題爲:

我可能會收到兩種不同的簡單數據。根據我收到的一個 ,運行一段特定的代碼。

這完全映射到選項2.我可能會或可能不會根據上下文嵌套函數。另外兩個選項會在您的目標和您的代碼之間造成不匹配。

選項1:

我會描述這種酮,爲的邏輯:

我有信息(或上下文)現在從我可以建立兩個不同的計算,其中的一個可能需要稍後運行。現在構建兩者,然後評估稍後需要的一個。

由於上下文或可用數據沒有變化,所以這實際上與您想要的邏輯不匹配。不管怎樣,你仍然處於相同的環境中,所以使其變得懶惰的額外複雜性簡單地混淆了函數的邏輯。

選項3:

我將描述此一者的邏輯爲:

我有一些數據,其可裝配到兩種情況之一。確定哪種情況持有需要一些複雜的邏輯,並且該邏輯也可能與確定整個函數的所需返回值所需的邏輯有一些重疊。將邏輯移到一個單獨的函數(本例中爲活動模式),然後使用活動模式的返回值來確定函數的結果值。

這一個將控制流程(確定接下來應該執行什麼代碼)與每種情況下執行的邏輯混合在一起。如果兩者之間沒有重疊,將控制流程從以下邏輯中分離出來會更加清楚。

因此,將代碼的結構與問題的結構相匹配,否則最終會有人想知道額外的代碼複雜性是如何實現的。