Сложно найти точное решение по ОП-вопросу.Вместо этого я собираюсь опубликовать некоторый код, который OP, возможно, может настроить в соответствии с потребностями.
Я определяю Result и ResultGenerator
type Result =
| Direct of string
| Delayed of (unit -> unit)
type ResultGenerator<'T> = G of (Result list -> 'T*Result list )
Генератор выдает значение и список прямых и отложенныхзначения, прямые значения - список строк выше, но смешанные с ними являются задержанными значениями.Мне нравится возвращать смешанные, чтобы порядок сохранялся.
Обратите внимание, что это версия того, что иногда называют State
монадой.
Помимо компонентов класса CE, таких как bind
иПостроители Я создал две функции: прямую и отложенную.
direct
используется для создания прямого значения, а delayed
задержанное (принимает функцию)
let direct v : ResultGenerator<_> =
G <| fun rs ->
(), Direct v::rs
let delayed d : ResultGenerator<_> =
G <| fun rs ->
(), Delayed d::rs
Для улучшения читабельности.Я определил задержанные trace
функции:
let trace m : ResultGenerator<_> =
G <| fun rs ->
(), Delayed (fun () -> printfn "%s" m)::rs
let tracef fmt = kprintf trace fmt
Из примера генератора:
let test =
builder {
do! direct "Hello"
do! tracef "A trace:%s" "!"
do! direct "There"
return 123
}
Был достигнут следующий результат:
(123, [Direct "Hello"; Delayed <fun:trace@37-1>; Direct "There"])
(Задержка будет печататьтрассировка при выполнении).
Надеюсь, что это может дать некоторые идеи о том, как атаковать актуальную проблему.
Полный источник:
open FStharp.Core.Printf
type Result =
| Direct of string
| Delayed of (unit -> unit)
type ResultGenerator<'T> = G of (Result list -> 'T*Result list )
let value v : ResultGenerator<_> =
G <| fun rs ->
v, rs
let bind (G t) uf : ResultGenerator<_> =
G <| fun rs ->
let tv, trs = t rs
let (G u) = uf tv
u trs
let combine (G t) (G u) : ResultGenerator<_> =
G <| fun rs ->
let _, trs = t rs
u trs
let direct v : ResultGenerator<_> =
G <| fun rs ->
(), Direct v::rs
let delayed d : ResultGenerator<_> =
G <| fun rs ->
(), Delayed d::rs
let trace m : ResultGenerator<_> =
G <| fun rs ->
(), Delayed (fun () -> printfn "%s" m)::rs
let tracef fmt = kprintf trace fmt
type Builder() =
class
member x.Bind (t, uf) = bind t uf
member x.Combine (t, u) = combine t u
member x.Return v = value v
member x.ReturnFrom t = t : ResultGenerator<_>
end
let run (G t) =
let v, rs = t []
v, List.rev rs
let builder = Builder ()
let test =
builder {
do! direct "Hello"
do! tracef "A trace:%s" "!"
do! direct "There"
return 123
}
[<EntryPoint>]
let main argv =
run test |> printfn "%A"
0