【问题标题】:Simplifying nested pattern matching F#简化嵌套模式匹配 F#
【发布时间】:2014-04-21 21:12:32
【问题描述】:

我正在用 F# 编写一个简单的表达式解析器,对于每个运算符,我只想支持一定数量的操作数(例如,两个用于 Modulo,三个用于 If)。这是我所拥有的:

type Operator =
    | Modulo
    | Equals
    | If

let processOperator operands operator =
    match operator with
    | Modulo ->
        match operands with
        | [ a:string; b:string ] -> (Convert.ToInt32(a) % Convert.ToInt32(b)).ToString()
        | _ -> failwith "wrong number of operands"
    | Equals ->
        match operands with
        | [ a; b ] -> (a = b).ToString()
        | _ -> failwith "wrong operands"
    | If ->
        match operands with 
        | [ a; b; c ] -> (if Convert.ToBoolean(a) then b else c).ToString()
        | _ -> failwith "wrong operands"

我想摆脱或简化内部列表匹配。实现这一目标的最佳方法是什么?我应该使用多个警卫吗?

【问题讨论】:

    标签: f# functional-programming pattern-matching discriminated-union guard-clause


    【解决方案1】:
    open System
    
    type Operator =
        | Modulo
        | Equals
        | If
    
    let processOperator operands operator =
        match (operator, operands) with
        | Modulo, [a: string; b] -> string ((int a) % (int b))
        | Equals, [a; b] -> string (a = b)
        | If, [a; b; c]  -> if Convert.ToBoolean(a) then b else c
        | _ -> failwith "wrong number of operands"
    

    但是我建议将操作数的这个逻辑移到解析器中,这样你就可以得到一个干净的运算符表达式,它更符合地道且易于处理,最后你会得到这样的结果:

    open System
    
    type Operator =
        | Modulo of int * int
        | Equals of int * int
        | If of bool * string * string
    
    let processOperator = function
        | Modulo (a, b) -> string (a % b)
        | Equals (a, b) -> string (a = b)
        | If (a, b, c)  -> if a then b else c
    

    【讨论】:

      【解决方案2】:

      折叠匹配的操作数:

      let processOperator operands operator =
          match operator, operands with
          | Modulo, [a; b] -> (Convert.ToInt32(a) % Convert.ToInt32(b)).ToString()
          | Equals, [a; b] -> (a = b).ToString()
          | If, [ a; b; c ] -> (if Convert.ToBoolean(a) then b else c).ToString()
          | _ -> failwith "wrong number of operands"
      

      如果可以的话,最好将数据类型更改为以下内容。

      type Operator =
          | Modulo of string * string
          | Equals of string * string
          | If of string * string * string
      

      那么在比赛中,你就不能再失败了。

      【讨论】:

      • 这不是把同一个问题推到代码的不同部分吗?
      • 您的意思是数据类型更改。是的。但是(Gustavo 和)我认为它属于那里,以及从整数和布尔值的所有转换 - 请参阅下面 Gustavo 的好答案。
      • 有趣的是,我们都同时回答了几乎相同的解决方案和相同的建议,这是一种设计味道(很好);)
      • @Gustavo & Søren :谢谢,我正在考虑您的第一个解决方案,但由于我可以更改数据类型,第二个似乎更好更干净。我不能同时标记两个答案,因此请给你们两个点赞,然后回答给 Søren(第一)。
      猜你喜欢
      • 1970-01-01
      • 2018-02-03
      • 1970-01-01
      • 2022-01-11
      • 2013-09-13
      • 1970-01-01
      • 1970-01-01
      • 2015-01-25
      • 1970-01-01
      相关资源
      最近更新 更多