Как передать значения объектов .net в F #? - PullRequest
7 голосов
/ 09 марта 2010

В настоящее время я изучаю 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.Load работает с объектом и возвращает void. Также XslCompiledTransform.Transform требует объект потока памяти и возвращает void.

Используемая выше стратегия заключается в добавлении объекта в конце (; mem) для возврата значения и обеспечении функционального программирования.

Когда мы хотим сделать это один за другим, в каждой строке есть функция с возвращаемым значением в конце:

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

Существует ли более правильный способ (с точки зрения функционального программирования) обрабатывать объекты .net и объекты, созданные в более OO-среде?

То, как я возвращал значение в конце, тогда везде были встроенные функции, что-то вроде хака, а не правильный способ сделать это.

Любая помощь очень ценится!

Ответы [ 2 ]

10 голосов
/ 09 марта 2010

Одним из больших преимуществ 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, что тоже функционально).

9 голосов
/ 09 марта 2010

Чтобы добавить еще один изящный совет Томасу, уже превосходному ответу, есть возможность показать эти функции, чтобы дать хорошее представление о том, насколько полезен 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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...