2010-04-29 12 views
6

¿Hay alguna forma en F # de cómo obtener el nombre de una variable pasada a una función?¿Cómo obtener un nombre de una variable que entra en una función como parámetro usando F #?

Ejemplo:

let velocity = 5 
let fn v = v.ParentName 
let name = fn velocity // this would return "velocity" as a string 

gracias de antemano

EDIT:

¿Por qué este código no funciona? Se compara como valor, por lo que no puedo recuperar el nombre de "variable".

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 

Respuesta

11

Para completar la respuesta de Marcelo, sí se puede utilizar citas para esta tarea:

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 <@[email protected]> 

printfn "%s" name 

Como se puede ver en el código, F # let-atado valores de definición superior (funciones o variables) se implementan como propiedades de una clase.

No encuentro más el enlace que muestra cómo una parte del código F # podría reescribirse de forma funcional con C#. Al ver el código, resulta obvio por qué necesita un patrón PropertyGet.

Ahora, si quiere evaluar la expresión también, necesitará instalar F# powerpack y hacer referencia FSharp.PowerPack.Linq en su proyecto.

Se añade un método EvalUntyped en Expr clase ..

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 <@[email protected]> 

printfn "%s %A" name value 

Si tiene que hacerlo por el método de una instancia, así es como lo haría:

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 <@[email protected]> 
printfn "%s" name 

let foo = new Foo() 

let methodName = fn <@[email protected]> 
printfn "%s" methodName 

Sólo para vuelva al fragmento de código que muestra el uso de EvalUntyped, puede agregar un parámetro de tipo explícito para Expr y un downcast (:?>) si desea/necesita mantener las cosas seguras:

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 <@[email protected]> //value has type int here 
printfn "%s %d" name value 
+0

Hola, gracias mucho! Una pregunta adicional. ¿Cómo obtengo un valor de la expresión? –

+0

Gracias! Y una pregunta final :) Si el fn es miembro de un tipo (member this.fn = ...), ¿cómo lo hago? –

+0

Para ser curioso, ¿por qué necesita recuperar el nombre de un valor/miembro? – Stringer

1

Usted puede ser capaz de lograr esto con citas de código:

let name = fn <@ velocity @> 

La función fn se pasará un objeto Expr, que se debe convertir a Quotations.Var (que sólo será si pasas una sola variable) y extraer el miembro de instancia Name.

+0

Hola, gracias por tu respuesta. ¿Cómo lo lanzo? esto: dejar que velExpr = <@ @ velocidad> Let fundido = velExpr:?> Quotations.Var no funciona –

0

Sobre la base de las soluciones anteriores, me salió con una solución más genérica donde se puede obtener el nombre de funciones, lambdas, valores, propiedades, métodos, métodos estáticos, campos públicos, tipos de unión:

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 
Cuestiones relacionadas