Учитывая следующее:
let f<'a,'b> = typeof<'a>.Name, typeof<'b>.Name //val f<'a,'b> : string * string
let g<'a,'b>() = typeof<'a>.Name, typeof<'b>.Name //val g<'a,'b> : unit -> string * string
следующие цитаты дают то, что кажется идентичным Expr
s:
let fq = <@ f<int,string> @> //Call (None, System.Tuple`2[System.String,System.String] f[Int32,String](), [])
let gq = <@ g<int,string>() @> //Call (None, System.Tuple`2[System.String,System.String] g[Int32,String](), [])
Копаясь с отладчиком, я не вижу способа сказать, что f
- это универсальное значение, тогда как g
- универсальная функция: возможно ли это сказать только из fq
и gq
? Поскольку F # может определить разницу между f
и g
в разных сборках, я думаю, что есть хороший шанс получить метаданные из цитаты. Хотя проблема может заключаться в том, что F #, по-видимому, на самом деле компилирует версию f
, которая является функцией unit -> string * string
(рассматривает дизассемблированный код; предположительно для взаимодействия с другими языками .NET), поэтому, если в цитате используется версия функции , информация может быть потеряна.
Обновление
Под руководством @ Томаса вот что я придумала:
let isGenericValue (mi:MemberInfo) =
try
let mOrV =
FSharpEntity.FromType(mi.DeclaringType).MembersOrValues
|> Seq.find (fun mOrV -> mOrV.CompiledName = mi.Name)
not mOrV.Type.IsFunction
with
| :? System.NotSupportedException -> true //for dynamic assemblies, just assume idiomatic generic value
Это можно использовать для сопоставления Patterns.Call(_,mi,_)
, где второй аргумент mi
является экземпляром MemberInfo
. Однако есть одна проблема: она не работает для динамических сборок (например, FSI).