f # Узкое размеченное объединение в предыдущей защите сопоставления с образцом (анализ типов на основе потока управления) - PullRequest
3 голосов
/ 03 августа 2020

Сужает ли F # типы, если они были сужены в предыдущей защите?

type FirstOption = bool option
type SecondOption = bool option

let foo first second =
     match first with
     | None -> false
     | Some value when second.IsSome ->
          // second is still Option<bool>
          sencond // x this doesn't fly.
     | Some value -> false

Я использовал Optopn.map/map2/map3 в этих случаях, но мне было интересно, возможно, я сделал что-то не так.

В случае TypeScript у них есть анализ на основе потока управления: https://github.com/microsoft/TypeScript/issues/2388

Ответы [ 3 ]

4 голосов
/ 03 августа 2020

Вы можете сопоставить шаблон для обоих вариантов (хорошо сопоставить кортеж из обоих вариантов)

для преобразования вашего примера:

let foo first second = 
  match (first, second) with
  | (None, _) -> false
  | (Some _, Some s) -> s
  | (Some x, None) -> false

который можно упростить до:

let foo first second =
   match (first, second) with
   | (Some _, Some s) -> s
   | _ -> false
3 голосов
/ 03 августа 2020

Насколько мне известно, F # не обеспечивает анализ типов на основе потока управления. Я думаю, что это противоречило бы дизайну F # как языка, ориентированного на выражения.

Однако F # предоставляет несколько механизмов для решения этой проблемы.

Первый - это вложенные match операторы с использованием сопоставления с образцом:

let foo first second =
  match first with
  | Some true ->
    match second with
    | Some true -> true
    | _ -> false
  | _ -> false

Второй способ, как указывали другие, состоит в использовании одного match, но в кортеже. Обратите внимание, что элементы в кортеже не обязательно должны иметь один и тот же тип!

let foo first second =
  match first, second with
  | Some true, Some true -> true
  | _ -> false

Обратите внимание, что в вашем конкретном примере, вероятно, проще всего использовать Option.defaultValue:

let foo first second = 
  (Option.defaultValue false first)
  && (Option.defaultValue false second)
3 голосов
/ 03 августа 2020

Я думаю, что F # не имеет анализа на основе потока управления как TypeScript, но в этом случае вы можете сделать следующее:

type FirstOption = bool option
type SecondOption = bool option

let foo (first: bool option) (second: bool option) =
     match first, second with
     | Some first, Some second ->
          // Now you have first and second which are bool values
          first && second // this flies like the wind :D
     | _ -> false
...