F # - Могу ли я вернуть дискриминированный союз из функции

У меня есть следующие типы:

type GoodResource = {
    Id:int;
    Field1:string }


type ErrorResource = {
    StatusCode:int;
    Description:string }

У меня есть следующий дискриминационный союз:

type ProcessingResult = 
    | Good of GoodResource
    | Error of ErrorResource

Затем нужно иметь функцию, которая будет иметь тип возврата разграниченного объединения ProcessingResult:

let SampleProcessingFunction value =
    match value with
    | "GoodScenario" -> { Id = 123; Field1 = "field1data" }
    | _ -> { StatusCode = 456; Description = "desc" }

Я пытаюсь сделать это. Компилятор дает указание, что он ожидает, что GoodResource будет возвратным типом. Что мне не хватает или я полностью об этом не так?

Ответ 1

В соответствии с этим SampleProcessingFunction возвращает два разных типа для каждой ветки.

Чтобы вернуть тот же тип, вам нужно создать DU (который вы сделали), но также явно указать случай DU, например:

let SampleProcessingFunction value =
    match value with
    | "GoodScenario" -> Good { Id = 123; Field1 = "field1data" }
    | _ -> Error { StatusCode = 456; Description = "desc" }

Вы можете спросить: "Почему компилятор не может определить правильный случай автоматически", но что произойдет, если ваш DU имеет два случая одного типа? Например:

type GoodOrError = 
    | Good of string
    | Error of string

В приведенном ниже примере компилятор не может определить, к какому случаю вы имеете в виду:

let ReturnGoodOrError value =
    match value with
    | "GoodScenario" -> "Goodness"
    | _ -> "Badness"

Итак, вам нужно использовать конструктор для нужного случая:

let ReturnGoodOrError value =
    match value with
    | "GoodScenario" -> Good "Goodness"
    | _ -> Error "Badness"

Ответ 2

Вы должны указать случай типа объединения, который хотите вернуть в любой ветки.

let SampleProcessingFunction value =
    match value with
    | "GoodScenario" -> { Id = 123; Field1 = "field1data" } |> Good
    | _ -> { StatusCode = 456; Description = "desc" } |> Error

Я предлагаю прочитать прекрасные статьи Скотта Улашина Железнодорожное ориентированное программирование

Ответ 3

{ Id = 123; Field1 = "field1data" } - это значение типа GoodResource, а не типа ProcessingResult. Чтобы создать значение типа ProcessingResult, вам нужно использовать один из двух его конструкторов: Good или Error.

Итак, ваша функция может быть написана так:

let SampleProcessingFunction value =
    match value with
    | "GoodScenario" -> Good { Id = 123; Field1 = "field1data" }
    | _ -> Error { StatusCode = 456; Description = "desc" }