Ошибка при распространении вычислительного выражения монады
Я пытаюсь написать вычислительное выражение, которое эффективно направляет предупреждения и ошибки из всех зависимых let! аргументы и объединяет их с результатом данного расчета. Проблема в получении списка ошибок от всех используемых let! объединить их после того, как результат расчета определен. Проиллюстрировать:
Учитывая тип
type ValueWithErrors<'value> =
| Value of 'value * string list
| Undefined of string list
и грубая функция привязки для этой стадии:
let public bind calculation = function
| Value(value, errors) ->
try
let result = calculation(value)
match result with
| Value(resultValue, resultErrors) -> Value(resultValue, (errors |> List.append resultErrors))
| Undefined(resultErrors) -> Undefined(errors |> List.append resultErrors)
with
| _ as ex -> Undefined(ex.Message :: errors)
| Undefined(errors) -> Undefined(errors)
Я хочу написать вычислительную функцию, которая позволяет мне делать что-то вроде:
calc {
let! value1 = ValueWithErrors (5, ["ERROR"])
let! value2 = ValueWithErrors (6, ["ERROR2"])
return (value1 + value2)
}
с результатом, равным Value(11, ["ERROR", "ERROR2"])
Таким образом, я определил неполный компоновщик следующим образом (заметьте, что Return() отсутствует)
type public ValueWithErrorsBuilder() =
member this.Bind(m, f) =
bind f m
member this.ReturnFrom(value) =
value
member this.Return(value) =
Value(value, []) // This is wrong, don't have access to previous binding
В C# я могу сделать это довольно легко с помощью специального метода расширения SelectMany(source, calc, resultSelector) для моего пользовательского типа, а синтаксис запроса LINQ переносит ошибки. Вот так:
from value1 in ValueWithErrors (5, ["ERROR"])
from value2 in ValueWithErrors (6, ["ERROR2"])
select (value1 + value2)
Я хотел бы сделать то же самое в F# - это вообще возможно?