0

我在工作流程中有一些代码,我想在其中获取函数的属性

表达是这样的

let! accounts = _accounts()

在我的绑定中,我有这个

member this.Bind(x,f) = 
    let attributes = 
      f.GetType()
       .GetCustomAttributes(typeof<myattribute>,false)

思路是获取函数_accounts()的属性。但是 f 代表 countinuation 而不是 _accounts ,所以无论如何我可以获得被调用函数的属性?

4

1 回答 1

5

我会后退一步 - 首先,您需要弄清楚您想要建模的计算是什么。根据您所说的,您可以保留一个包含一些审核日志信息列表的结果:

type Audited<'T> = 
  { Log : string list
    Result : 'T }

标准的基本计算构建器只会创建空日志ReturnBind简单地连接日志:

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 }

这仍然需要引用 - 我想你可以尝试其他方法来做到这一点 - 但关键是你有一个基本的计算,它真正定义了结构是什么。

于 2015-09-10T23:32:37.767 回答