function - funciones anonimas matlab
¿Cómo obtener un nombre de una variable que entra en una función como parámetro usando F#? (3)
¿Hay alguna forma en F # de cómo obtener un nombre de una variable pasada a una función?
Ejemplo:
let velocity = 5
let fn v = v.ParentName
let name = fn velocity // this would return "velocity" as a string
Gracias de antemano
EDITAR:
¿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
En base a las soluciones anteriores, obtuve una solución más genérica donde 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
Es posible que pueda lograr esto con citas de código:
let name = fn <@ velocity @>
La función fn
pasará un objeto Expr
, que debe convertir a Quotations.Var
(que solo será si pasa una única variable) y extraerá el miembro de instancia de Name
.
Para completar la respuesta de Marcelo, sí, puedes usar 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 <@velocity@>
printfn "%s" name
Como puede ver en el código, los valores de definición superior de F # let-bound (funciones o variables) se implementan como propiedades de una clase.
No puedo encontrar más el enlace que muestra cómo una parte del código F # podría reescribirse de una manera funcional con C #. Al ver el código, resulta obvio por qué necesita un patrón PropertyGet
.
Ahora, si también desea evaluar la expresión, necesitará instalar F # powerpack y hacer referencia a FSharp.PowerPack.Linq
en su proyecto.
Agrega un método Expr
clase 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
Si necesita 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 <@velocity@>
printfn "%s" name
let foo = new Foo()
let methodName = fn <@foo.Bar@>
printfn "%s" methodName
Solo para volver al fragmento de código que muestra el uso de EvalUntyped
, puede agregar un parámetro de tipo explícito para Expr
y un Expr
( :?>
) Si desea / necesita mantener los tipos seguros.
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