F#用于构建状态和延迟执行的计算表达式

F#用于构建状态和延迟执行的计算表达式,f#,computation-expression,F#,Computation Expression,我希望构建一个计算表达式,其中可以表达以下内容: 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" // ne

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

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
}
并且能够从
x
列表中获取:

[| "Message 1"
   "Message 2"
   "Message 3"
   "Message 4" |]
没有
printfn
被调用,但是能够在以后执行它(如果有意义的话)

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

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


我尝试了一些方法,但不确定是否可行。

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

我定义了Result和ResultGenerator

type Result =
  | Direct  of string
  | Delayed of (unit -> unit)

type ResultGenerator<'T> = G of (Result list -> 'T*Result list )
为了提高可读性,我定义了延迟
跟踪
函数:

let trace m : ResultGenerator<_> =
  G <| fun rs ->
    (), Delayed (fun () -> printfn "%s" m)::rs

let tracef fmt = kprintf trace fmt
取得了以下成果:

(123, [Direct "Hello"; Delayed <fun:trace@37-1>; Direct "There"])
(123,[直接“你好”;延迟;直接“那里”)
(延迟将在执行时打印跟踪)

希望这能为如何解决实际问题提供一些思路

完整资料来源:

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
打开FStharp.Core.Printf
类型结果=
|字符串的直接形式
|延迟的(单位->单位)
类型ResultGenerator printfn“%s”m::rs
让tracef fmt=kprintf trace fmt
类型生成器()=
班
成员x.Bind(t,uf)=Bind t uf
成员x.联合收割机(t,u)=联合收割机tu
成员x.返回v=值v
成员x.ReturnFrom t=t:ResultGenerator
结束
让我们跑(G t)=
设v,rs=t[]
v、 List.rev rs
让builder=builder()
试一试=
建筑商{
直接说“你好”
do!tracef“A跟踪:%s”!“
做!直接“那里”
返回123
}
[]
让主argv=
运行测试|>printfn“%A”
0

我可以想出几种可能的解决方案,但您希望如何返回延迟的操作?在您的示例中,
是否应该让
也延迟?延迟操作是否可以返回值,在这种情况下,以下表达式可能依赖于该值,并且CE在延迟操作执行之前无法完成。感谢响应。
let
s可能会延迟。延迟的工作无法返回值。谢谢,这正是我要找的指导。我不再迷路了
(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