Run*_* FS 0 f# computation-expression
我在工作流程中有一些代码,我想将属性赋予函数
表达是这样的
let! accounts = _accounts()
在我的约束中,我有这个
member this.Bind(x,f) = 
    let attributes = 
      f.GetType()
       .GetCustomAttributes(typeof<myattribute>,false)
我们的想法是获取函数_accounts()的属性.但是f代表countinuation而不是_accounts,所以无论如何我可以得到被调用函数的属性?
我退后一步 - 首先,你需要弄清楚你想要建模的计算是什么.根据您的说法,您可以使用一些审核日志信息列表保存结果:
type Audited<'T> = 
  { Log : string list
    Result : 'T }
标准基本计算构建器只会创建空登录Return并Bind简单地连接日志:
type AuditBuilder() =
  member x.Return(v) = { Log = []; Result = v }
  member x.Bind(c, f) = 
    let fr = f c.Result
    { fr with Log = c.Log @ fr.Log }
let audit = AuditBuilder()
你可以真正使用它,前提是你的accounts函数会返回一个正确的Audited<'T>值:
let accounts () = 
  { Result = 40
    Log = ["accounts"] }
let stocks () = 
  { Result = 2
    Log = ["stocks"] }
audit {
  let! a = accounts()
  let! s = stocks()
  return a + s }
现在,问题是,我们可以使它更好一点,所以这accounts()不一定是特殊的功能.你可以通过各种方式做到这一点 - 但现在更多的是关于创造Audited<'T>价值的问题!
做这样的事情的一种方法是将报价传递给Bind.一个非常基本和简单的实现如下所示:
let plain () = 123
open Microsoft.FSharp.Quotations
type AuditBuilder with
  member x.Bind(e:Expr<'T>, f:'T -> _) = 
    match e with
    | Patterns.Call(None, mi, []) -> 
        let r = f (mi.Invoke(null, [| |]) :?> 'T)
        { r with Log = r.Log @ [mi.Name] }
    | _ -> failwith "invalid"
这会增加一个重载Bind,让你"调用"一个带引号的函数,但它会自动提取名称:    
audit {
  let! p = <@ plain() @>
  return p }
这仍然需要引用 - 我想你可以尝试其他方法来做到这一点 - 但关键的想法是你有一个基本的计算,它真正定义了结构是什么.