Ошибка при распространении вычислительного выражения монады

Я пытаюсь написать вычислительное выражение, которое эффективно направляет предупреждения и ошибки из всех зависимых 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# - это вообще возможно?

0 ответов

Другие вопросы по тегам