F#:嵌套的可区分联合和匹配

发布于 2025-01-01 22:11:19 字数 1226 浏览 1 评论 0原文

我有 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. 警告上收到 此规则将永远不会匹配
  2. Update(stype) 上,我在第一个 match stype 我在此表达式上得到不完整的模式匹配。例如,值“Producers”可能表示模式未涵盖的情况。

所以问题是为什么我会收到这两个警告?我是否错过了匹配工作方式中的某些内容?

I have 2 nested discriminated unions:

type ServiceTypes =
    | Contexts
    | Context of int
    | Producers

type ServiceActions =
    | Get of ServiceTypes
    | Update of ServiceTypes

And a nested match statement:

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")))

The goal is to build a request string with a call looking like that req.Send(Update Producers).

Anyway for a reason that I do not understand, the compiler gives me 2 warnings:

  1. on the Update(stype) I get a This rule will never be matched
  2. on the the first match stype I get a Incomplete pattern matches on this expression. For example, the value 'Producers' may indicate a case not covered by the pattern(s).

So the question is why do I get these 2 warnings? Did I miss something on the way matching works?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

水中月 2025-01-08 22:11:19

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

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")

这会实现与您的代码完全相同的效果。

While nested match expressions are sometimes warranted, in this particular case I would write a more readable single-level match, if I were you:

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")

which achieves exactly the same effect as your code.

云淡风轻 2025-01-08 22:11:19

您的右括号位置错误。

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

应该是

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

确实,为了清楚起见,我会去掉所有无关的括号(在这种情况下实际上是每个括号):

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"

我个人认为这更具可读性,但当然这是主观的,所以YMMV。

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.

鲜血染红嫁衣 2025-01-08 22:11:19

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

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) 永远不会匹配。因此,所有编译器警告都是合理的。

你似乎过度使用了拟态;这是一个清理版本:

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"

Since you closed the paratheses in the wrong point, your code actually becomes:

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")))

Obviously you can see the first match stype with doesn't cover Producers and the last pattern Update(stype) never matches due to the previous pattern of _. Therefore, all compiler warnings are justified.

You seem to overuse paratheses; here is a cleaned up version:

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"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文