我目前正在学习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
此代码使用.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
是否有更正确的方法(在函数式编程方面)来处理在更多OO环境中创建的.net对象和对象?
我最后返回值的方式然后在任何地方都有内联函数感觉有点像黑客而不是正确的方法。
非常感谢任何帮助!
答案 0 :(得分: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
第二个例子:
let doc = new XmlDocument("doc")
doc.Load("report.xml")
doc.AppendNode(new XmlElement("Happy"))
这并不意味着你以任何方式摆脱功能风格 - 在使用.NET类时,有很多机会使用功能风格。例如,您可以使用诸如Seq.filter
和Seq.map
(或序列表达式)之类的高阶函数来处理数据集合(或XML元素)。您仍然可以使用高阶函数编写抽象。
System.Xml
命名空间非常必要,因此功能样式空间不大。但是,生成以XML格式存储的数据的代码可以完全正常运行。可能值得一看 LINQ to XML 类(在.NET 3.5+中),因为它们以更加功能性编程友好的方式设计(因为它们应该与LINQ配合使用) ,这也是功能)。
答案 1 :(得分:9)
为Tomas添加另一个精彩的提示已经很好的答案,是有机会讨论这些功能,以便很好地指示F#的用处,甚至在需要时使用命令式编码技术。
示例1 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
在阅读this帖后,我想到了一个更进一步的方法,让我们来讨论这个功能。这意味着(如果我们选择)我们只能传递函数一个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
)
)
所以我们可以做到以下几点:
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"