Есть ли какой-либо путь в F#, как добраться, название переменной передало в функцию?
Пример:
let velocity = 5
let fn v = v.ParentName
let name = fn velocity // this would return "velocity" as a string
Заранее спасибо
Править:
Почему этот код не работает? Это подобрано как значение, таким образом, я не могу получить "переменное" имя.
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
Для завершения ответа Марсело, да, вы можете использовать цитаты для этой задачи:
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
Как вы можете видеть в коде, F # позволяет ограничивать верхние значения определения (функции или переменные) реализуются как свойства класса.
Я больше не могу найти ссылку, которая показывает, как часть кода F # может быть функционально переписана с помощью C #. Глядя на код, становится очевидно, зачем вам нужен шаблон PropertyGet
.
Теперь, если вы хотите также оценить выражение, вам нужно будет установить F # powerpack и ссылку FSharp.PowerPack.Linq
в вашем проекте.
Он добавляет метод EvalUntyped
в класс Expr
..
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
Если вам нужно сделать это для метода экземпляра, вот как я это сделаю:
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
Чтобы вернуться к фрагменту кода, показывающему использование EvalUntyped
, вы можете добавить явное параметр типа для Expr
и понижающего преобразования (:?>
), если вы хотите / должны сохранить безопасность типов:
let fn (e:Expr<´T>) = //using ´ instead of ' to avoid colorization screw-up
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
Вы можете добиться этого с помощью цитат кода:
let name = fn <@ velocity @>
В функцию fn
будет передан объект Expr
, который необходимо преобразовать в Quotations.Var.
(что будет только в том случае, если вы передадите одну переменную) и извлеките член экземпляра Name
.