2016-12-07 40 views
1

下面的行不會編譯:如何在使用「函數」語法執行模式匹配時檢索值?

| IsNeither -> sprintf "%i" // ??? 

這裏的功能,這行屬於:

let run = function 

    | IsFizzBuzz -> "Fizz Buzz" 
    | IsFizz  -> "Fizz" 
    | IsBuzz  -> "Buzz" 
    | IsNeither -> sprintf "%i" // Doesn't compile 

這裏就是整個程序: 模塊溫度

let (|IsFizz|IsBuzz|IsFizzBuzz|IsNeither|) = function 
    | n when n % 3 = 0 && 
      n % 5 = 0 -> IsFizzBuzz 
    | n when n % 3 = 0 -> IsFizz 
    | n when n % 5 = 0 -> IsBuzz 
    | n ->    IsNeither 

let run = function 

    | IsFizzBuzz -> "Fizz Buzz" 
    | IsFizz  -> "Fizz" 
    | IsBuzz  -> "Buzz" 
    | IsNeither -> sprintf "%i" // Doesn't compile 

let result = [1..16] |> List.map(run) 

我仍然可以使用簽名上的「函數」語法提取值嗎?

實施例:

let (|IsFizz|IsBuzz|IsFizzBuzz|IsNeither|) = function 

回答

9

有是不要求你重新定義你的模式,通過使用as關鍵字的解決方案:

let run = function 
    | IsFizzBuzz -> "Fizz Buzz" 
    | IsFizz  -> "Fizz" 
    | IsBuzz  -> "Buzz" 
    | IsNeither as n -> sprintf "%i" n 

這很好地工作在活動模式,匹配識別聯合的情況,等等。一個突出的用例是類型檢查,在那裏你有一個像| :? string as s

7

最簡單的解決方案將是使該圖案的值部分。

let (|IsFizz|IsBuzz|IsFizzBuzz|IsNeither|) = function 
    | n when n % 3 = 0 && 
      n % 5 = 0 -> IsFizzBuzz 
    | n when n % 3 = 0 -> IsFizz 
    | n when n % 5 = 0 -> IsBuzz 
    | n    -> IsNeither n 

let run = function 
    | IsFizzBuzz -> "Fizz Buzz" 
    | IsFizz  -> "Fizz" 
    | IsBuzz  -> "Buzz" 
    | IsNeither n -> sprintf "%i" n 
6

有一個neither情況下比賽表明,並不是所有的值可以被劃分爲「域」等等Partial Active Pattern可能是一個賭注三選一。
關聯與AND pattern它可以簡化代碼(在一些變化成本)

// common code extracted and inlined (optional) 
let inline isDivisibleBy divisor dividend = 
    if dividend % divisor = LanguagePrimitives.GenericZero 
    then Some() 
    else None 

let (|Fizz|_|) = isDivisibleBy 3 
let (|Buzz|_|) = isDivisibleBy 5 

let run = function Fizz & Buzz -> "FizzBuzz" 
       | Fizz  -> "Fizz" 
       | Buzz  -> "Buzz" 
       | x   -> string x 

let result = List.map run [1 .. 16] 

走這路人們甚至可以得到有利於擺脫那些FizzBuzz函數相對於一般IsDivisibleBy

let inline (|IsDivisibleBy|_|) divisor dividend = 
    if dividend % divisor = LanguagePrimitives.GenericZero 
    then Some() 
    else None 

let run = function IsDivisibleBy 3 & IsDivisibleBy 5 -> "FizzBuzz" 
       | IsDivisibleBy 3     -> "Fizz" 
       | IsDivisibleBy 5     -> "Buzz" 
       | x         -> string x 

let result = List.map run [1 .. 16] 

甚至可以說,這樣,如果你仍然想那些FizzBuzz你仍然可以做

let (|Fizz|_|) = (|IsDivisibleBy|_|) 3 
let (|Buzz|_|) = (|IsDivisibleBy|_|) 5