Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top