【问题标题】:How do I retrieve a value when using the "function" syntax to perform pattern matching?使用“函数”语法执行模式匹配时如何检索值?
【发布时间】:2016-12-07 14:19:28
【问题描述】:

以下行无法编译:

| 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

【问题讨论】:

    标签: f# pattern-matching


    【解决方案1】:

    使用as 关键字,有一个不需要您重新定义模式的解决方案:

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

    这很好地适用于活动模式、匹配有区别的联合案例等。一个突出的用例是类型检查,您可以在其中匹配 | :? string as s

    【讨论】:

      【解决方案2】:

      最简单的解决方案是将值作为模式的一部分。

      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
      

      【讨论】:

        【解决方案3】:

        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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-09-18
          • 2021-02-09
          • 1970-01-01
          • 2011-01-17
          • 1970-01-01
          • 2011-07-05
          相关资源
          最近更新 更多