Короткий и простой ответ первым.Я вернусь позже для более длинного ответа.
Если вы создаете монолитное приложение, предлагается создать только один тип ошибки для всего приложения:
type AllErrors =
| FileNotFound of string
| InvalidJsonStructure of string
| OtherErrors ...
Это дастодно хорошее место, где все ошибки определены, и вы можете создать единую printError
и другие функции обработки ошибок.
Иногда это невозможно, например, если ваш код является модульным, и каждый модуль имеет свой собственныйErrorType, тогда у вас есть два варианта, все равно создайте уникальный тип и сопоставьте его или создайте вложенный, составной тип, как вы это сделали.Это твое решение.В обоих случаях вы используете Result.mapError
Синтаксически существует много способов сделать это.Чтобы избежать вложенных match
s, вы используете Result.bind
и Result.mapError
let readJson (path : string) : Result<Json, ReadJsonError> =
readFile path
|> Result.mapError ReadFileError
|> Result.bind (fun content ->
parseJson content
|> Result.mapError JsonParseError
)
Если бы у вас было result
Вычислительное выражение:
type Builder() =
member inline this.Return x = Ok x
member inline this.ReturnFrom x = (x:Result<_,_>)
member this.Bind (w , r ) = Result.bind r w
member inline this.Zero () = Ok ()
let result = Builder()
, то это выглядело бы какэто:
let readJson (path : string) : Result<Json, ReadJsonError> = result {
let! content = readFile path |> Result.mapError ReadFileError
return! parseJson content |> Result.mapError JsonParseError
}
с операторами:
let (>>= ) vr f = Result.bind f vr
let (|>>.) vr f = Result.mapError f vr
это может быть так:
let readJson (path : string) : Result<Json, ReadJsonError> =
readFile path |>>. ReadFileError
>>= fun content ->
parseJson content |>>. JsonParseError
или это:
let readJson (path : string) : Result<Json, ReadJsonError> =
path
|> readFile
|>>. ReadFileError
>>= fun content ->
content
|> parseJson
|>>. JsonParseError
илидаже это:
let readJson (path : string) : Result<Json, ReadJsonError> =
path |>
readFile |>>.
ReadFileError >>=
fun content ->
content |>
parseJson |>>.
JsonParseError
Хорошо, этот последний просто для удовольствия.Я не защищаю ваш код, подобный этому.
также вы можете просто создать унифицированную версию ваших функций:
let readFileU = readFile >> Result.mapError ReadFileError
let readJsonU = parseJson >> Result.mapError JsonParseError
и связать их с помощью оператора Клейсли:
let (>=>) f g p = f p |> Result.bind g
let readJson = readFileU >=> readJsonU
Еще один ответ будет позже ...