f# - 更改异步工作流构建器以计算步骤?

标签 f# monads

我的理解是,工作流构建器所做的是首先“构建”表达式,然后再执行它。所以考虑到它首先构建表达式,它应该能够在实际执行之前计算 let! 语句的数量,对吧?然后它应该能够注入(inject)一些监控进度的日志记录?那么是否可以重新设计 async 构建器以自动报告进度并消除下面的 printfn 冗余?

 async {
   let! a = doSomething1 ()
   printfn "%d/%d" 1 4
   let! b = doSomething2 a
   printfn "%d/%d" 2 4
   let! c = doSomething3 b
   printfn "%d/%d" 3 4
   let! d = doSomething4 c
   printfn "%d/%d" 4 4
   return d
 }

对于循环,我想只是假设整个循环是一个步骤。此处只有顶级表达式算作步骤。

(请注意,如果有一种方法可以在不创建全新的工作流程构建器的情况下执行此操作,我想这也很好)。

请注意,我已经完成了 a) 制作一个只迭代任务的“任务”迭代器(但是你失去了例如 use 处理,所以它最终是不合适的),和b) 制作一个任务计数器,但始终必须手动播种和迭代,所以我希望有更好的东西。

最佳答案

当您用标签 monads 标记问题时,我将从理论上的吹毛求疵开始。你想做的实际上不是 monad。问题是 monad 需要特定的法则(参见 the Haskell page on monads )。对于 F#,这意味着以下两个代码段的含义应该相同:

let computation1 = 
  async { let! x = m
          return x }
let computation2 = m

对于您建议的扩展,情况并非如此,因为 computation1还有一个let!computation2 .现在,我认为这实际上不是问题 - 日志记录仍然有用(即使在某些情况下它可能会给出与您预期不同的结果)。

将此功能添加到 F# async 并不容易 - 问题是您需要定义自己的类型来替换(或包装)标准 Async<'T> .该类型需要存储步数。如果您可以将步数存储在其他地方(例如一些可变计数器),那么您只需要重新定义 async 的计算构建器 | .

这是一个最小的例子,它做这样的事情 - 它只打印 "step"对于每个 let! :

// A custom computation builder that redirects all operations to
// the standard 'async' builder, but prints "step" in the Bind method
type LogAsyncBuilder() = 
  member x.Bind(c1, f) = async { 
    let! arg = c1
    printfn "step!" 
    return! f arg }
  member x.Return(v) = async.Return(v)
  member x.ReturnFrom(c) = async.ReturnFrom(c)

// An instance of our custom computation builder
let logAsync = LogAsyncBuilder()

// Example that prints 'step' 4 times (for every Bind - let!)
let doSomething n = logAsync {
  return n + 10 }

logAsync {
  let! a = doSomething 0
  let! b = doSomething a
  let! c = doSomething b
  let! d = doSomething c
  return d }
|> Async.RunSynchronously

关于f# - 更改异步工作流构建器以计算步骤?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18291812/

相关文章:

javascript - 如何编写TaskT Monad Transformer来组合异步计算和其他效果?

haskell - 说明 Category、Monoid 和 Monad 的简单例子?

Haskell:从 IO [[String]] 生成 HaTeX 输出

f# - 如何在函数内将静态参数传递给 f# 中的类型提供程序

f# - F# 中的快捷等式检查?

f# - F# 和 C# lambda 之间的互操作

haskell - 将 IO [可能是字符串] 过滤为 IO [字符串]

f# - 完整模式匹配的编译时约束

C++ 到 F# 的平滑转换

haskell - 关于 >>= Monad 运算符的签名