Извлечение имени переменной - PullRequest
1 голос
/ 10 апреля 2020

Как мы можем построить функцию в F #, которая выводит имя переданной переменной? Например:

let someVar1 = "x"
getVarname someVar1 //output would be "someVar1"

let someVar2 = "y"
getVarname someVar2 //output would be "someVar2"

let f toString = fun a -> printfn "%s: %d" (toString a) a
let x = 1
f getVarname x      //output would be: "x: 1"

Я нашел подобный вопрос в C# здесь ( получить имя переменной или параметра ), но я не смог заставить его работать в F #.

Ответы [ 2 ]

3 голосов
/ 10 апреля 2020

Если вы используете кавычки и методы c, вы уже можете захватить имя переменной в F # 4, используя атрибут ReflectedDefinition. Метод Demo.GetVarName stati c в следующем примере возвращает имя переменной, используемой в качестве аргумента, вместе со значением:

open Microsoft.FSharp.Quotations

type Demo = 
  static member GetVarName([<ReflectedDefinition(true)>] x:Expr<int>) = 
    match x with
    | Patterns.WithValue(_, _, Patterns.ValueWithName(value, _, name)) ->
        name, value :?> int
    | _ -> failwithf "Argument was not a variable: %A" x

let test ()= 
  let yadda = 123
  Demo.GetVarName(yadda)

test()

Это работает для локальных переменных, как в функции test() выше , Для переменных верхнего уровня (которые фактически скомпилированы как свойства) вам также необходимо добавить регистр для PropertyGet:

match x with
| Patterns.WithValue(_, _, Patterns.ValueWithName(value, _, name)) -> 
    name, value :?> int
| Patterns.WithValue(value, _, Patterns.PropertyGet(_, pi, _)) -> 
    pi.Name, value :?> int
| _ -> failwithf "Argument was not a variable: %A" x
1 голос
/ 10 апреля 2020

Реализация nameof имеет оператор в ядре F #, но биты компилятора F # 5 еще не отправлены. Когда это произойдет, вы можете использовать его, чтобы получить имя символа.

let someVar1 = None
let name = nameof someVar1 // name = "someVar1"

На данный момент мы можем, возможно, использовать оператор динамического c, чтобы получить нам прокладку, которую вы в конечном итоге сможете заменить на nameof

let name = ()
let (?) _ name = string name

Использование:

let someVar1 = None
let name = name?someVar1

Это не слишком плохо читается, и вы получаете некоторую степень автозаполнения.

Если вы действительно хотите чтобы иметь возможность получить локальное имя и значение на сайте вызова, есть цитаты.

let printVar = function
|  ValueWithName(value, _type, name) -> printfn "%s = %A" name value 
| _ -> ()

Хотя использование немного шумное.

let someVar1 = 12
printVar <@ someVar1 @> //prints someVar1 = 12
...