简化嵌套模式匹配F#

时间:2014-03-16 18:49:19

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

我在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"

我想摆脱或简化内部列表匹配。完成此任务的最佳方法是什么?我应该使用多个警卫吗?

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:3)

折叠匹配的操作数:

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

然后在比赛中,你不能再失败了。