F#计算表达式以建立状态并推迟执行



我希望构建一个计算表达式,其中我可以表达以下内容:

let x = someComputationExpression {
do! "Message 1"
printfn "something 1"
do! "Message 2"
printfn "something 2"
do! "Message 3"
printfn "something 3"
let lastValue = 4
do! "Message 4"
// need to reference values across `do!`
printfn "something %s" lastValue
}

并且能够从CCD_ 1获取列表:

[| "Message 1"
"Message 2"
"Message 3"
"Message 4" |]

不需要调用printfn,但可以稍后执行它(如果有意义的话)。

它不需要使用do!关键字,它可以是yieldreturn,无论它工作需要什么。

换句话说,我希望能够在计算表达式中收集一些状态,并将稍后可以执行的工作(printfn)排队。

我试过几件事,但不确定是否可能。

从OP问题中找出精确的解决方案有点困难。相反,我将发布一些OP可能可以根据需要进行调整的代码。

我定义了Result和ResultGenerator

type Result =
| Direct  of string
| Delayed of (unit -> unit)
type ResultGenerator<'T> = G of (Result list -> 'T*Result list )

生成器生成一个值以及直接值和延迟值的列表,直接值是上面的字符串列表,但与它们混合的是延迟值。我喜欢混合退货,这样订单就可以保留下来。

请注意,这是一个有时被称为Statemonad的版本。

除了类CE组件(如bind和Builders)之外,我还创建了两个直接和延迟的函数。

direct用于创建直接值,x0用于创建延迟值(取函数)

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

相关内容

  • 没有找到相关文章

最新更新