在绑定中获取 f 的属性
gettings attributes of f in a bind
我在工作流中有一些代码,我想在其中获取函数的属性
表达式是这样的
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
函数会 return 一个正确的 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
,让您 "call" 引用函数,但它会自动提取名称:
audit {
let! p = <@ plain() @>
return p }
这仍然需要引用 - 我猜你可以尝试其他方法 - 但关键思想是你有一个基本的计算,它真正定义了结构是什么。
我在工作流中有一些代码,我想在其中获取函数的属性
表达式是这样的
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
函数会 return 一个正确的 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
,让您 "call" 引用函数,但它会自动提取名称:
audit {
let! p = <@ plain() @>
return p }
这仍然需要引用 - 我猜你可以尝试其他方法 - 但关键思想是你有一个基本的计算,它真正定义了结构是什么。