F #: вложенные дискриминируемые объединения и сопоставление

У меня есть 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 я получаю Неполные совпадения с шаблоном для этого выражения. Например, значение «Производители» может указывать на случай, не охватываемый шаблоном (ами).

Итак, вопрос в том, почему я получаю эти 2 предупреждения? Я что-то пропустил в процессе сопоставления?


person Nicolas Guillaume    schedule 03.02.2012    source источник


Ответы (3)


Ваша закрывающая скобка стоит не на том месте.

| 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.

person ildjarn    schedule 03.02.2012
comment
Арф ... Я думал, что не понял сопоставления с образцом: P По крайней мере, это была просто глупая синтаксическая ошибка. Отличная демонстрация того, как избавиться от лишних скобок. Мне она очень нравится (я обновил свой код). Спасибо вам большое за ваше время! - person Nicolas Guillaume; 04.02.2012

Хотя вложенные выражения соответствия иногда оправданы, в этом конкретном случае я бы написал более читаемое одноуровневое соответствие, если бы я был вами:

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

который дает точно такой же эффект, как и ваш код.

person kkm    schedule 04.02.2012

Поскольку вы закрыли паразиты не в том месте, ваш код на самом деле выглядит следующим образом:

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"
person pad    schedule 03.02.2012