Допустим, мы имеем простой F # цитата:Генерация параметризованные F # котировок
type Pet = { Name : string } let exprNonGeneric = <@@ System.Func(fun (x : Pet) -> x.Name) @@>
Полученная цитата как:
val exprNonGeneri : Expr = NewDelegate (System.Func`2[[FSI_0152+Pet, FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], x, PropertyGet (Some (x), System.String Name, []))
Теперь я хочу обобщать, так что я вместо типа «Pet "и свойство" Name "Я мог бы использовать произвольный тип и метод/свойство, определенные на нем. Вот что я пытаюсь сделать:
let exprGeneric<'T, 'R> f = <@@ System.Func<'T, 'R>(%f) @@> let exprSpecialized = exprGeneric<Pet, string> <@ (fun (x : Pet) -> x.Name) @>
Полученное выражение теперь отличается:
val exprSpecialized : Expr = NewDelegate (System.Func`2[[FSI_0152+Pet, FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], delegateArg, Application (Lambda (x, PropertyGet (Some (x), System.String Name, [])), delegateArg))
Как вы можете видеть, разница между первым и вторым выражением является то, что в первом случае выражение верхнего уровня NewDelegate содержит PropertyGet, а второе выражение переносит PropertyGet в выражении Application/Lambda. И когда я передаю это выражение внешнему коду, он не ожидает такой структуры выражения и терпит неудачу.
Поэтому мне нужно каким-то образом построить обобщенную версию цитаты, поэтому, когда она становится специализированной, итоговая цитата является точным соответствием < @@ System.Func (fun (x: Pet) -> x.Name) @@ >. Это возможно? Или это только выбор, чтобы вручную применить сопоставление шаблонов с генерируемой цитатой и преобразовать ее в то, что мне нужно?
ОБНОВЛЕНИЕ. В качестве обходного пути я осуществил следующий адаптер:
let convertExpr (expr : Expr) = match expr with | NewDelegate(t, darg, appl) -> match (darg, appl) with | (delegateArg, appl) -> match appl with | Application(l, ldarg) -> match (l, ldarg) with | (Lambda(x, f), delegateArg) -> Expr.NewDelegate(t, [x], f) | _ -> expr | _ -> expr | _ -> expr
Это делает работу - теперь я могу преобразовать выражение с 1-го по 2-й форме. Но мне интересно узнать, может ли это быть достигнуто простым способом, без пересечения деревьев выражений.
Благодарим за ответ и большое предложение. Тем не менее, я все еще придерживаюсь связанной проблемы: возможно ли вообще подключить простой делегат F # (например, fun x -> x.Name) к общей цитате, которая не зависит от фактического типа, например, цитата № 2 выше. Это похоже на то, что делают насмешливые фреймворки: они определяют некоторые выражения без знания конкретных интерфейсов и ввода конкретных типов. Кажется, я не могу этого добиться в F #. –
@Vagif - Я не уверен, что понимаю ваш вопрос. Не могли бы вы подробнее рассказать о том, что вы пытаетесь сделать? – kvb
Мне нужно отправить interop между F # и C#. C# ожидает выражения LINQ определенного типа. Я могу записать его в F # жестко закодированным образом, но для этого хочу создать общую оболочку F #. Эта обертка должна иметь возможность принимать в качестве входных lambdas как «fun x -> x.Name» и преобразовывать их в цитаты. Я начинаю подозревать, что это невозможно в общем случае. –