Below the computation expression I'm trying to implement. The value is wrapped in a tuple where the second item of the tuple is a list of strings representings the log entries along the way.
type LoggerBuilder() =
member this.Bind(vl : 'a * string list, f) =
let value = vl |> fst
let logs = vl |> snd
let appendLogs logs tpl =
let value = vl |> fst
let log = vl |> snd
(value, logs |> List.append log)
(f value) |> appendLogs logs
member this.Return(x) =
(x, [])
However, when I run the following, I didn't get the expected result. I wonder where did I missed.
let log = new LoggerBuilder()
let a = log {
let! a = (1, ["assign 1"])
let! b = (2, ["assign 2"])
return a + b
}
// Result:
val a : int * string list = (1, ["assign 1"; "assign 1"])
// Expected:
val a : int * string list = (3, ["assign 1"; "assign 2"])
Update
To avoid this error, pass the --warnon:1182
to the command prompt of fsi
or fsc
. This will raise a warning for unused "variables".
The problem is in the implementation of appendLogs
function. There, you don't use the tpl
parameter, but use the outer scope's vl
instead, which contains only value and log for the current part of computation. You also need to flip arguments for List.append
, otherwise the log will be backwards.
With both these fixes, your function would look like this:
let appendLogs logs tpl =
let value = tpl |> fst
let log = tpl |> snd
(value, log |> List.append logs)
And with this you should get the expected result.
I also would like to add that by using destructuring in the first method parameter and later in a let
binding, your Bind
function could be implemented somewhat simpler:
member this.Bind((x, log) : 'a * string list, f) =
let y, nextLog = f x
y, List.append log nextLog