I'm trying to write a computational expression that effectively threads warnings and errors from all dependent let! arguments and combines them with a result of a given calculation. The problem is getting the error list from all used let! to concatenate them after the result of the calculation defined. To illustrate:
Given the type
type ValueWithErrors<'value> =
| Value of 'value * string list
| Undefined of string list
and a crude bind function for this stage:
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)
I want to write a computation function that allows me to do something like:
calc {
let! value1 = ValueWithErrors (5, ["ERROR"])
let! value2 = ValueWithErrors (6, ["ERROR2"])
return (value1 + value2)
}
with the result being Value(11, ["ERROR", "ERROR2"])
So I've defined an incomplete builder as thus (note the Return() impl missing)
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
In C# I can do this pretty easily with a custom SelectMany(source, calc, resultSelector) extension method on my custom type and the LINQ query syntax carries through the errors. Like so:
from value1 in ValueWithErrors (5, ["ERROR"])
from value2 in ValueWithErrors (6, ["ERROR2"])
select (value1 + value2)
I would like to do the same in F# - is this possible at all?