Digamos que tenemos un simple F # cita:Generación parametrizados F # citas
type Pet = { Name : string } let exprNonGeneric = <@@ System.Func(fun (x : Pet) -> x.Name) @@>
La cita resultante es como:
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, []))
Ahora quiero generalizar, así que en vez de escribir "Pet "y propiedad" Nombre "Podría usar un tipo arbitrario y método/propiedad definidos en él. Esto es lo que estoy tratando de hacer:
let exprGeneric<'T, 'R> f = <@@ System.Func<'T, 'R>(%f) @@> let exprSpecialized = exprGeneric<Pet, string> <@ (fun (x : Pet) -> x.Name) @>
La expresión resultante es ahora diferente:
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))
Como se puede ver, la diferencia entre la primera y la segunda expresión es que en el primer caso, el la expresión NewDelegate de nivel superior contiene PropertyGet, mientras que la segunda expresión ajusta PropertyGet en una expresión Application/Lambda. Y cuando paso esta expresión a un código externo, no espera esa estructura de expresión y falla.
Así que necesito alguna manera de construir una versión generalizada de la cita, por lo que cuando se especialice, la cita resultante es una coincidencia exacta de < @@ System.Func (diversión (x: Pet) -> x.Name) @@ >. es posible? ¿O solo hay opciones para aplicar manualmente la coincidencia de patrones a una cita generada y transformarla en lo que necesito?
ACTUALIZACIÓN. Como solución implementé el adaptador siguiente:
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
Se hace el trabajo - ahora puedo convertir la expresión de 1ra a 2da forma. Pero estoy interesado en saber si esto se puede lograr de una manera simple, sin atravesar los árboles de expresión.
Gracias por la respuesta y una gran sugerencia. Sin embargo, todavía estoy atascado con un problema relacionado: ¿es posible conectar un simple delegado F # (por ejemplo, diversión x -> x.Name) en una cita genérica que es independiente del tipo real, como la cita # 2 anterior. Esto es similar a lo que hacen los marcos burlones: definen algunas expresiones sin conocer las interfaces concretas e inyectan tipos concretos. No parece ser capaz de lograr esto en F #. –
@Vagif: no estoy seguro de entender su pregunta. ¿Podría entrar un poco más de detalle sobre lo que está tratando de hacer? – kvb
Necesito enviar interoperabilidad entre F # y C#. C# espera la expresión de LINQ de cierto tipo. Puedo escribirlo en F # de manera codificada, pero quiero construir un contenedor F # genérico para esto. Este contenedor debería poder tomar como entrada lambdas como "fun x -> x.Name" y convertirlos en citas. Estoy empezando a sospechar que esto no es posible en el caso general. –