Я в настоящее время изучаю 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
Этот код преобразовывает XML-документ с использованием документа XSLT объекты .NET. Отметьте XslCompiledTransform. Загрузка работает над объектом и возвратами пусто. Также XslCompiledTransform. Преобразуйте требует объекта memorystream и возвращается пусто.
Вышеупомянутая используемая стратегия состоит в том, чтобы добавить объект в конце (; мадам), чтобы возвратить значение и заставить функциональное программирование работать.
Когда мы хотим сделать этого за другим, у нас есть функция на каждой строке с возвращаемым значением в конце:
let myFunc =
new XmlDocument("doc")
|> fun a -> a.Load("report.xml"); a
|> fun a -> a.AppendChild(new XmlElement("Happy")); a
Существует ли более корректный путь (с точки зрения функционального программирования) для обработки объектов .NET и объектов, которые были созданы в большем количестве среды OO?
Путем я возвратил значение в конце, затем имел подставляемые функции, везде чувствует немного как взлом а не корректный способ сделать это.
Любая справка значительно ценится!
Одним из больших преимуществ F # является то, что он позволяет смешивать стиль функционального программирования с другими стилями (а именно объектно-ориентированным и императивным). Поскольку большинство библиотек .NET являются объектно-ориентированными и императивными, лучший способ получить доступ к функциональным возможностям .NET из F # - это просто использовать императивные функции 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, который тоже работает).
Чтобы добавить еще один отличный совет к уже отличному ответу Томаса, есть возможность каррировать эти функции, чтобы дать хорошее представление о том, насколько полезен F #, даже с использованием императивного методы кодирования при необходимости.
В примере 1 Томас использовал преобразование xml-документа в 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
Прочитав этот пост, я подумал о том, как сделать еще один шаг и позволить нам каррировать эту функцию .Это означает (если мы выберем) мы можем передать функции только документ XSL, она вернет функцию, которая преобразует любой документ xml с заданным документом XSL:
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"