[英]How to get a name of a variable coming into a function as a parameter using F#?
Is there any way in F# how to get a name of a variable passed into a function?在 F# 中有什么方法可以获取传递给函数的变量的名称吗?
Example:例子:
let velocity = 5
let fn v = v.ParentName
let name = fn velocity // this would return "velocity" as a string
Thank you in advance先感谢您
EDIT:编辑:
Why this code does not work?为什么这段代码不起作用? It is matched as value, so I can not retrieve the "variable" name.它作为值匹配,所以我无法检索“变量”名称。
type Test() =
let getName (e:Quotations.Expr) =
match e with
| Quotations.Patterns.PropertyGet (_, pi, _) -> pi.Name + " property"
| Quotations.Patterns.Value(a) -> failwith "Value matched"
| _ -> failwith "other matched"
member x.plot v = v |> getName |> printfn "%s"
let o = new Test()
let display () =
let variable = 5.
o.plot <@ variable @>
let runTheCode fn = fn()
runTheCode display
For completing Marcelo's answer, yes you can use quotations for this task:要完成 Marcelo 的回答,是的,您可以为此任务使用引号:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
let velocity = 5
let fn (e:Expr) =
match e with
| PropertyGet (e, pi, li) -> pi.Name
| _ -> failwith "not a let-bound value"
let name = fn <@velocity@>
printfn "%s" name
As you can see in the code, F# let-bound top definition values (functions or variables) are implemented as properties of a class.正如您在代码中看到的,F# let-bound 顶级定义值(函数或变量)被实现为类的属性。
I can't find anymore the link that shows how a piece of F# code could be rewritten in a functional way with C#.我再也找不到显示如何使用 C# 以功能方式重写一段 F# 代码的链接。 Seeing the code, it becomes obvious why you need a PropertyGet
pattern.看到代码,很明显为什么需要PropertyGet
模式。
Now if you want to evaluate the expression too, you will need to install F# powerpack and reference FSharp.PowerPack.Linq
in your project.现在,如果您也想对表达式求值,则需要在项目中安装F# FSharp.PowerPack.Linq
并引用FSharp.PowerPack.Linq
。
It adds an EvalUntyped
method on Expr
class..它在Expr
类上添加了一个EvalUntyped
方法。
open Microsoft.FSharp.Linq.QuotationEvaluation
let velocity = 5
let fn (e:Expr) =
match e with
| PropertyGet (eo, pi, li) -> pi.Name, e.EvalUntyped
| _ -> failwith "not a let-bound value"
let name, value = fn <@velocity@>
printfn "%s %A" name value
If you need to do it for the method of an instance, here's how I would do it:如果您需要为实例的方法执行此操作,我会这样做:
let velocity = 5
type Foo () =
member this.Bar (x:int) (y:single) = x * x + int y
let extractCallExprBody expr =
let rec aux (l, uexpr) =
match uexpr with
| Lambda (var, body) -> aux (var::l, body)
| _ -> uexpr
aux ([], expr)
let rec fn (e:Expr) =
match e with
| PropertyGet (e, pi, li) -> pi.Name
| Call (e, mi, li) -> mi.Name
| x -> extractCallExprBody x |> fn
| _ -> failwith "not a valid pattern"
let name = fn <@velocity@>
printfn "%s" name
let foo = new Foo()
let methodName = fn <@foo.Bar@>
printfn "%s" methodName
Just to come back on the code snippet showing usage of EvalUntyped
, you can add an explicit type parameter for Expr
and a downcast ( :?>
) if you want/need to keep things type-safe:回到显示EvalUntyped
用法的代码片段,如果您想/需要保持类型安全,您可以为Expr
添加显式类型参数和向下转换 ( :?>
):
let fn (e:Expr<'T>) =
match e with
| PropertyGet (eo, pi, li) -> pi.Name, (e.EvalUntyped() :?> 'T)
| _ -> failwith "not a let-bound value"
let name, value = fn <@velocity@> //value has type int here
printfn "%s %d" name value
You might be able to achieve this with code quotations:您可以使用代码引用来实现这一点:
let name = fn <@ velocity @>
The fn
function will be passed an Expr
object, which it must cast to Quotations.Var
(which it will only be if you pass a single variable) and extract the Name
instance member. fn
函数将传递一个Expr
对象,它必须将其转换为Quotations.Var
(只有在传递单个变量时才会如此)并提取Name
实例成员。
Based on the previous solutions I came out with a more generic solution where you can get the name of functions, lambdas, values, properties, methods, static methods, public fields, Union types:基于之前的解决方案,我提出了一个更通用的解决方案,您可以在其中获取函数、lambda、值、属性、方法、静态方法、公共字段、联合类型的名称:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
let cout (s:string)= System.Console.WriteLine (s)
let rec getName exprs =
let fixDeclaringType (dt:string) =
match dt with
| fsi when fsi.StartsWith("FSI_") -> "Fsi"
| _ -> dt
let toStr (xDeclType: System.Type) x = sprintf "%s.%s" (fixDeclaringType xDeclType.Name) x
match exprs with
| Patterns.Call(_, mi, _) ->
toStr mi.DeclaringType mi.Name
| Patterns.Lambda(_, expr) ->
getName expr
| Patterns.PropertyGet (e, pi, li) ->
toStr pi.DeclaringType pi.Name
| Patterns.FieldGet (_, fi) ->
toStr fi.DeclaringType fi.Name
| Patterns.NewUnionCase(uci, _) ->
toStr uci.DeclaringType uci.Name
| expresion -> "unknown_name"
let value = ""
let funcky a = a
let lambdy = fun(x) -> x*2
type WithStatic =
| A | B
with static member StaticMethod a = a
let someIP = System.Net.IPAddress.Parse("10.132.0.48")
getName <@ value @> |> cout
getName <@ funcky @> |> cout
getName <@ lambdy @> |> cout
getName <@ WithStatic.A @> |> cout
getName <@ WithStatic.StaticMethod @> |> cout
getName <@ someIP.MapToIPv4 @> |> cout
getName <@ System.Net.IPAddress.Parse @> |> cout
getName <@ System.Net.IPAddress.Broadcast @> |> cout
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.