你如何在F#中传递.net对象值?

Rus*_*ell 7 .net f#

我目前正在学习F#和函数式编程(来自C#背景),我有一个关于在处理过程中使用.net CLR对象的问题.

描述我的问题的最好方法是举个例子:

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
Run Code Online (Sandbox Code Playgroud)

此代码使用.net对象将XSLT文档转换为XML文档.注意XslCompiledTransform.Load适用于对象,并返回void.此外,XslCompiledTransform.Transform需要一个memorystream对象并返回void.

上面使用的策略是在末尾添加对象(; mem)以返回值并使函数式编程工作.

当我们想要一个接一个地做这个时,我们在每一行都有一个函数,最后有一个返回值:

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

是否有更正确的方法(在函数编程方面)来处理在更多OO环境中创建的.net对象和对象?

我在最后返回值的方式然后在各处都有内联函数感觉有点像黑客而不是正确的方法来做到这一点.

任何帮助是极大的赞赏!

Tom*_*cek 10

F#的一大好处是它允许您将函数式编程风格与其他样式(即面向对象和命令式)混合使用.由于大多数.NET库都是面向对象且必不可少的,因此从F#访问.NET功能的最佳方法是简单地使用F#的命令功能.这意味着在使用.NET对象时,惯用的F#代码看起来几乎就像C#.

编辑:以下略微修改的示例显示如何将XSL转换包装到一个函数中,该函数获取输入文件的名称和xsl文件的名称.它返回MemoryStream输出的写入位置:

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
Run Code Online (Sandbox Code Playgroud)

第二个例子:

let doc = new XmlDocument("doc")   
doc.Load("report.xml")
doc.AppendNode(new XmlElement("Happy"))
Run Code Online (Sandbox Code Playgroud)

这并不意味着你以任何方式摆脱功能风格 - 在使用.NET类时,有很多机会使用功能风格.例如,您可以使用高阶函数(如Seq.filterSeq.map/或序列表达式)来处理数据集合(或XML元素).您仍然可以使用高阶函数编写抽象.

System.Xml命名空间是非常必要的,所以不实用的风格的空间.但是,生成以XML格式存储的数据的代码可以完全正常运行.看看LINQ to XML类(在.NET 3.5+中)可能是值得的,因为它们以更加功能性编程友好的方式设计(因为它们应该与LINQ一起使用,它也很有用).


Rus*_*ell 9

为Tomas添加另一个漂亮的提示已经很好的答案,就是有机会讨论这些函数,以便很好地指示F#的有用性,甚至在需要时使用命令式编码技术.

使用Tomas的示例是在给定xsl文档的情况下转换xml文档:

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
Run Code Online (Sandbox Code Playgroud)

阅读这篇文章后,我想到了一个更进一步的方法,让我们来讨论这个功能.这意味着(如果我们选择)我们只能传递函数一个XSL文档,它将返回一个函数,它将转换给定指定XSL文档的任何xml文档:

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
        )
    )
Run Code Online (Sandbox Code Playgroud)

所以我们可以做到以下几点:

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"
Run Code Online (Sandbox Code Playgroud)