6

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
4

3 に答える 3

12

マルセロの答えを完成させるために、はい、このタスクに引用を使用できます:

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# の let バインドされた最上位の定義値 (関数または変数) は、クラスのプロパティとして実装されます。

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>) = 
  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
于 2010-04-29T11:07:23.880 に答える
1

コードの引用でこれを達成できるかもしれません:

let name = fn <@ velocity @>

fn関数にはオブジェクトが渡され、Exprこれにキャストする必要がありQuotations.Var(単一の変数を渡す場合のみ)、Nameインスタンス メンバーを抽出します。

于 2010-04-29T09:49:10.073 に答える
0

以前のソリューションに基づいて、関数、ラムダ、値、プロパティ、メソッド、静的メソッド、パブリック フィールド、ユニオン型の名前を取得できる、より一般的なソリューションを思い付きました。

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  
于 2017-07-14T09:12:19.000 に答える