F # - Opción de extracción de Expr

¿Hay alguna forma de extraer un parámetro de un Expr?

Un ejemplo:

let hasStringOption (e:Expr<string option>) =
    let myOption : string option = ..some code to get the string option from e

¿Cómo obtendría el string option dentro de Expr y asignarlo a myOption?

preguntado el 16 de mayo de 11 a las 19:05

Depende, si tiene <@ Some (fx) @>, ¿le gustaría evaluar la llamada a la función o no? Si es así, use Eval como lo menciona wmeyer; De lo contrario, la solución de Stephen es el camino a seguir. -

3 Respuestas

En tu ejemplo, string option representa la expresión tipo de retorno, por lo que la expresión en sí podría ser arbitrariamente compleja y requiere algún tipo de estrategia de evaluación como la de PowerPack, como ha demostrado @wmeyer.

Pero si realmente tienes un string option expresión Puede utilizar los patrones activos de cotización de la biblioteca estándar y la reflexión para implementar su propia estrategia de evaluación (aquí se muestra la opción genérica):

module P = Microsoft.FSharp.Quotations.Patterns

let extract (expr:Expr<'a option>) =
    match expr with
    | P.NewUnionCase (uci, args) ->
        if uci.Name = "Some" then
            match args.Head with
            | P.Value(value, ty) -> Some(value :?> 'a)
        else
            None:('a option)

let example1 = extract <@ None:int option @>
let example2 = extract <@ Some("hello world") @>

y de hecho, este enfoque puede ser parte de su propia estrategia para evaluar de forma recursiva expresiones arbitrarias utilizando patrones activos y de reflexión en lugar de la estrategia LINQ intermedia lenta y limitada de PowerPack.

contestado el 17 de mayo de 11 a las 01:05

gracias por la función ordenada :) - Pero ... ¿por qué usas None:('a option)? ¿De qué se trata todo esto? - reflujo

Hola @ebb, de nada. La :('a option) parte de None:('a option) es solo una anotación de tipo que usé originalmente para ayudar al compilador a inferir el tipo de retorno de extract. Pero resulta innecesario ya que el Some(value :?> 'a) rama es una pista suficiente (escribí la rama Ninguno primero). Por otro lado, :int option is necesario para ayudar al compilador a inferir el tipo último de example1. Pero también podría haberlo hecho colocando la anotación de tipo en el propio ejemplo1: let example1:int option = extract <@ None @> - Stephen Swensen

Con la FSharp.PowerPack.Linq.dll referenciado puede hacer:

  open Microsoft.FSharp.Quotations 
  open Microsoft.FSharp.Linq.QuotationEvaluation


  let hasStringOption (e:Expr<string option>) =
      let myOption : string option = e.Eval()
      myOption.IsSome

  printfn "%A" (hasStringOption <@ Some "hello" @>)
  printfn "%A" (hasStringOption <@ None @>)

Sin embargo, según se informa, esto es bastante lento y utiliza expresiones LINQ como paso intermedio.

contestado el 16 de mayo de 11 a las 23:05

Lamentablemente (o no), no puede evaluar las citas de F #. F # PowerPack tiene una capacidad limitada para compilar citas para expresiones LINQ (que se pueden evaluar).

contestado el 16 de mayo de 11 a las 23:05

Implementé un evaluador de cotizaciones personalizado basado en la reflexión que ahora forma parte de Unquote, code.google.com/p/unquote, a partir de la versión 2.0.0. Lo he medido hasta 50 veces más rápido que el evaluador de PowerPack y también admite muchas más expresiones. - Stephen Swensen

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.