2

我有 2 个嵌套的歧视联合:

type ServiceTypes =
    | Contexts
    | Context of int
    | Producers

type ServiceActions =
    | Get of ServiceTypes
    | Update of ServiceTypes

还有一个嵌套的匹配语句:

let s_action = match action with
               | Get(stype) -> sprintf "Get%s" (match stype with
                                                | Contexts -> sprintf "Contexts"
                                                | Context(id)  -> (sprintf "Context/%d" id))
                                                | _ -> raise (RequestException("get"))
               | Update(stype) -> sprintf "Update%s" (match stype with
                                                      | Producers -> (sprintf "Producers")
                                                      | _ -> raise (RequestException("update")))

目标是构建一个请求字符串,调用看起来像这样req.Send(Update Producers)

无论如何,出于我不明白的原因,编译器给了我 2 个警告:

  1. Update(stype)我得到一条这条规则永远不会被匹配
  2. 第一次match stype在这个表达式上得到一个不完整的模式匹配。例如,值“生产者”可能表示模式未涵盖的情况。

所以问题是为什么我会收到这两个警告?我在匹配的过程中错过了什么吗?

4

3 回答 3

15

虽然有时需要使用嵌套匹配表达式,但在这种特殊情况下,如果我是你,我会编写一个更具可读性的单级匹配:

let s_action = 
   match action with
   | Get Contexts     -> "GetContexts"
   | Get (Context id) -> sprintf "GetContext/%d" id
   | Update Producers -> "UpdateProducers"
   | Get _    -> raise (RequestException "get")
   | Update _ -> raise (RequestException "update")

它实现了与您的代码完全相同的效果。

于 2012-02-04T02:52:16.113 回答
6

Your closing parenthesis is in the wrong place.

| Context(id)  -> (sprintf "Context/%d" id))
| _ -> raise (RequestException("get"))

should be

| Context(id)  -> (sprintf "Context/%d" id)
| _ -> raise (RequestException("get")))

Indeed, for the sake of clarity I would get rid of all extraneous parentheses (which in this case is actually every parenthesis):

let s_action =
    match action with
    | Get stype    -> match stype with
                        | Contexts   -> "Contexts"
                        | Context id -> sprintf "Context/%d" id
                        | _          -> RequestException "get" |> raise
                      |> sprintf "Get%s"
    | Update stype -> match stype with
                        | Producers -> "Producers"
                        | _         -> RequestException "update" |> raise
                      |> sprintf "Update%s"

Personally I find this more readable, but of course that's subjective so YMMV.

于 2012-02-03T22:50:23.430 回答
2

由于您在错误的位置关闭了括号,因此您的代码实际上变为:

let s_action =
  match action with
  | Get(stype) -> sprintf "Get%s" (match stype with
                                   | Contexts -> sprintf "Contexts"
                                   | Context(id)  -> (sprintf "Context/%d" id))
  | _ -> raise (RequestException("get")) (* Closing parenthesis should be here *)
  | Update(stype) -> sprintf "Update%s" (match stype with
                                         | Producers -> (sprintf "Producers")
                                         | _ -> raise (RequestException("update")))

显然你可以看到第一个match stype with没有覆盖Producers,最后一个模式Update(stype)永远不会匹配,因为之前的模式是_. 因此,所有编译器警告都是合理的。

你似乎过度使用了paratheses;这是一个清理后的版本:

let s_action =
 match action with
 | Get stype -> sprintf "Get%s" <| match stype with
                                   | Contexts -> sprintf "Contexts"
                                   | Context id -> sprintf "Context/%d" id
                                   | _ -> raise <| RequestException "get"
 | Update stype -> sprintf "Update%s" <| match stype with
                                         | Producers -> sprintf "Producers"
                                         | _ -> raise <| RequestException "update"
于 2012-02-03T22:59:39.543 回答