F# 异步让! & return!计算表达式
F# Async let! & return! computation expression
我已经开始阅读有关计算表达式的资料,据我所知 - 它有一些默认和自定义的隐藏实现。
我会提供我理解的东西,请指正。
例如,在本例中,我们定义了一个自定义实现来使用 let!。让每一个表情都绑定到让!记录器块内将记录到控制台。
type LoggingBuilder() =
let log p = printfn "expression is %A" p
member this.Bind(x, f) =
log x
f x
member this.Return(x) = x
let logger = new LoggingBuilder()
let loggedWorkflow =
logger {
let! x = 42
let! y = 43
let! z = x + y
return z
}
我记不太清了,但我读过如果我们不提供它的实现 - 它有一些内置的默认值。例如一些工作流,当它收到 None 时,它会停止整个工作流程,将 return 只是 none,如果它 return 一些 - 代码将继续 -> 这是否是默认设置?
由于感叹号后面的关键字在幕后有一些额外的功能,那么在 async {} 块中它是什么?
举个例子。
let printerAgent =
MailboxProcessor.Start
(fun inbox ->
// the message processing function
let rec messageLoop () =
async {
// read a message
let! msg = inbox.Receive()
// process a message
printfn "message is: %s" msg
// loop to top
return! messageLoop ()
}
// start the loop
messageLoop ())
我假设 let! msg = inbox.Receive()
会在收到 None 时停止工作流。关于return!我真的不知道。
不,计算表达式方法没有默认实现。如果你想要 Async<'T option>
的特殊行为,你可以向 AsyncBuilder
添加一个扩展方法。看起来你想短路一个 Async<unit>
,所以你会想要这样的东西:
type FSharp.Control.AsyncBuilder with
member async.Bind(x: Async<'T option>, f: 'T -> Async<unit>) =
async.Bind(x, function
| Some x -> f x
| None -> async.Return())
计算表达式可以解决多个 Bind
实现之间的重载,但您需要小心:如果类型不明确,F# 将选择在类型本身上实现的方法(在这种情况下,内置绑定) 通过扩展方法。
// Here `x` is used as an `int`, so F# knows that it needs to use
// my Bind implementation.
async {
let! x = myAsyncIntOption
let y = x + 1
return ()
}
// Here the type of `x` is unspecified, so F# chooses to use
// the built-in Bind implementation and `x` has type `int option`.
async {
let! x = myAsyncIntOption
return ()
}
现在,我已经说了可以 做什么,但我不建议实际这样做。相反,我会做一些更明确的事情:
let printerAgent =
MailboxProcessor.Start
(fun inbox ->
// the message processing function
let rec messageLoop () =
async {
// read a message
match! inbox.Receive() with
| None -> return ()
| Some msg ->
// process a message
printfn "message is: %s" msg
// loop to top
return! messageLoop ()
}
// start the loop
messageLoop ())
我已经开始阅读有关计算表达式的资料,据我所知 - 它有一些默认和自定义的隐藏实现。
我会提供我理解的东西,请指正。
例如,在本例中,我们定义了一个自定义实现来使用 let!。让每一个表情都绑定到让!记录器块内将记录到控制台。
type LoggingBuilder() =
let log p = printfn "expression is %A" p
member this.Bind(x, f) =
log x
f x
member this.Return(x) = x
let logger = new LoggingBuilder()
let loggedWorkflow =
logger {
let! x = 42
let! y = 43
let! z = x + y
return z
}
我记不太清了,但我读过如果我们不提供它的实现 - 它有一些内置的默认值。例如一些工作流,当它收到 None 时,它会停止整个工作流程,将 return 只是 none,如果它 return 一些 - 代码将继续 -> 这是否是默认设置?
由于感叹号后面的关键字在幕后有一些额外的功能,那么在 async {} 块中它是什么?
举个例子。
let printerAgent =
MailboxProcessor.Start
(fun inbox ->
// the message processing function
let rec messageLoop () =
async {
// read a message
let! msg = inbox.Receive()
// process a message
printfn "message is: %s" msg
// loop to top
return! messageLoop ()
}
// start the loop
messageLoop ())
我假设 let! msg = inbox.Receive()
会在收到 None 时停止工作流。关于return!我真的不知道。
不,计算表达式方法没有默认实现。如果你想要 Async<'T option>
的特殊行为,你可以向 AsyncBuilder
添加一个扩展方法。看起来你想短路一个 Async<unit>
,所以你会想要这样的东西:
type FSharp.Control.AsyncBuilder with
member async.Bind(x: Async<'T option>, f: 'T -> Async<unit>) =
async.Bind(x, function
| Some x -> f x
| None -> async.Return())
计算表达式可以解决多个 Bind
实现之间的重载,但您需要小心:如果类型不明确,F# 将选择在类型本身上实现的方法(在这种情况下,内置绑定) 通过扩展方法。
// Here `x` is used as an `int`, so F# knows that it needs to use
// my Bind implementation.
async {
let! x = myAsyncIntOption
let y = x + 1
return ()
}
// Here the type of `x` is unspecified, so F# chooses to use
// the built-in Bind implementation and `x` has type `int option`.
async {
let! x = myAsyncIntOption
return ()
}
现在,我已经说了可以 做什么,但我不建议实际这样做。相反,我会做一些更明确的事情:
let printerAgent =
MailboxProcessor.Start
(fun inbox ->
// the message processing function
let rec messageLoop () =
async {
// read a message
match! inbox.Receive() with
| None -> return ()
| Some msg ->
// process a message
printfn "message is: %s" msg
// loop to top
return! messageLoop ()
}
// start the loop
messageLoop ())