2010-03-08 13 views
7

Actualmente estoy aprendiendo F # y programación funcional en general (desde un fondo de C#) y tengo una pregunta sobre el uso de objetos .NET CLR durante mi procesamiento.¿Cómo se pasan los valores de los objetos .net en F #?

La mejor manera de describir mi problema será dar un ejemplo:

let xml = new XmlDocument() 
      |> fun doc -> doc.Load("report.xml"); doc 

let xsl = new XslCompiledTransform() 
      |> fun doc -> doc.Load("report.xsl"); doc 

let transformedXml = 
    new MemoryStream() 
     |> fun mem -> xsl.Transform(xml.CreateNavigator(), null, mem); mem 

Este código se transforma un documento XML con un documento XSLT utilizando objetos .NET. Nota XslCompiledTransform.Load funciona en un objeto y devuelve vacío. También XslCompiledTransform.Transform requiere un objeto de tren de memoria y devuelve vacío.

La estrategia anterior utilizada es agregar el objeto al final (el; mem) para devolver un valor y hacer que la programación funcional funcione.

Cuando queremos hacer esto, uno tras otro tenemos una función en cada línea con un valor de retorno al final:

let myFunc = 
    new XmlDocument("doc") 
    |> fun a -> a.Load("report.xml"); a 
    |> fun a -> a.AppendChild(new XmlElement("Happy")); a 

¿Hay una manera más correcta (en términos de programación funcional) para manejar .net objetos y objetos que se crearon en un entorno más OO?

La forma en que devolvió el valor al final y luego tuve funciones en línea en todas partes se siente como un hack y no es la forma correcta de hacerlo.

¡Cualquier ayuda es muy apreciada!

Respuesta

10

Una de las grandes ventajas de F # es que le permite mezclar el estilo de programación funcional con otros estilos (es decir, orientado a objetos e imperativo). Como la mayoría de las bibliotecas .NET están orientadas a objetos e imperativas, la mejor manera de acceder a la funcionalidad .NET desde F # es simplemente usar las características imperativas de F #. Esto significa que cuando se trabaja con objetos .NET, el código F # idiomático se verá casi como C#.

EDITAR: El siguiente ejemplo muestra cómo ligeramente modificada para envolver transformación XSL en una función que toma el nombre del archivo de entrada y un nombre de archivo XSL. Devuelve el MemoryStream donde la salida se escribió:

let transformDocument inputFile xslFile = 
    let doc = new XmlDocument() 
    doc.Load(inputFile) 
    let xsl = new XslCompiledTransform() 
    xsl.Load(xslFile) 

    let mem = new MemoryStream() 
    xsl.Transform(xml.CreateNavigator(), null, mem) 
    mem 

Y el segundo ejemplo:

let doc = new XmlDocument("doc") 
doc.Load("report.xml") 
doc.AppendNode(new XmlElement("Happy")) 

Esto no quiere decir que usted está apartándose del estilo funcional en modo alguno - hay muchas oportunidades para usar estilo funcional cuando se trabaja con clases .NET. Por ejemplo, puede usar funciones de orden superior como Seq.filter y Seq.map (o expresiones de secuencia) para procesar colecciones de datos (o elementos XML). Todavía puede escribir abstracciones usando funciones de orden superior.

El espacio de nombre System.Xml es muy imperativo, por lo que no hay mucho espacio para el estilo funcional. Sin embargo, el código que genera los datos que almacena en XML puede ser completamente funcional. Puede valer la pena mirar las clases LINQ to XML (en .NET 3.5+), ya que están diseñadas de una manera mucho más funcional y amigable con la programación (ya que se supone que funcionan bien con LINQ, que también es funcional)

+0

Gracias por la gran respuesta :) ¿Puedo poner el código (digamos el segundo ejemplo que escribió) todo en una sola función que devuelve el objeto doc? – Russell

+0

Sí, definitivamente! Esa es la mejor manera de ocultar los bits imperativos (feos) del resto del (agradable) programa funcional. Edité la respuesta (el primer ejemplo), de modo que muestra una función simple para transformar archivos XML utilizando archivos XSL. –

+0

¡Excelente gracias por los ejemplos detallados y explicaciones! :) – Russell

9

Para agregar otra punta ingeniosa a Tomas, la respuesta ya es excelente, es la oportunidad de curry estas funciones para dar una buena indicación de cuán útil es F #, incluso utilizando técnicas de codificación imperativas cuando sea necesario.

El ejemplo 1 Tomas utilizado fue transformar un documento XML dado un documento XSL:

let transformDocument inputFile xslFile = 
    let doc = new XmlDocument() 
    doc.Load(inputFile) 
    let xsl = new XslCompiledTransform() 
    xsl.Load(xslFile) 

    let mem = new MemoryStream() 
    xsl.Transform(xml.CreateNavigator(), null, mem) 
    mem 

Después de leer this puesto, pensé en una manera de ir un paso más allá y nos permitirá de curry esta función. Lo que esto significa es (si elegimos), podemos pasar a la función sólo un documento XSL, devolverá una función que va a transformar cualquier documento XML dado el documento XSL especificado:

let transform = 
    (fun xsl -> 
     let xsl_doc = new XslCompiledTransform() 
     xsl_doc.Load(string xsl) 

     (fun xml -> 
      let doc = new XmlDocument() 
      doc.Load(string xml) 
      let mem = new MemoryStream() 
      xsl_doc.Transform(doc.CreateNavigator(), null, mem) 
      mem 
     ) 
    ) 

para que pudiéramos hacer lo siguiente:

let transform_report_xsl = transform "report.xsl" 
let transform_style_xsl = transform "style.xsl" 

transform_report_xsl "report.xml" 
transform_report_xsl "report2.xml" 
transform_style_xsl "page.xml" 
+1

¡Este es un gran ejemplo! También podría especificar solo un argumento para mi función original (porque las funciones F # se curried automáticamente). Sin embargo, su versión es mucho mejor: cuando le da solo un parámetro, cargará la transformación XSL, por lo que el procesamiento de archivos XML individuales será más rápido. Este truco (o patrón :-)) generalmente se llama _pre-computation_. –

+0

Gracias por la información :) También separa la funcionalidad más (obliga al código XSL a estar en una función y al código XML en la otra) lo que lo hace más legible. – Russell

+0

Hoy mismo he pensado en esta solución al pasar funciones mientras hago javascript con jQuery. ¡Las definiciones de funciones de vuelta pueden ser muy útiles! – Russell

Cuestiones relacionadas