Кодирование практики для F#

Я плескался с F# в Visual Studio 2010. Я - разработчик с большим опытом проектирования кода/архитектуры на объектно-ориентированных языках, таких как C# и Java.

Для расширения моего набора навыков и справки принимают лучшие решения, я пробую различные языки, чтобы сделать разные вещи. В особенности приобретите навык кодирования "правильно" с помощью функциональных языков (в этом случае F#).

Простой пример генерирует некоторый XML, затем добавляя некоторые фильтры для устранения некоторых элементов.

Вот мой код:

open System
open System.Xml.Linq


let ppl:(string * string) list = [
    ("1", "Jerry"); 
    ("2", "Max"); 
    ("3", "Andrew");
]

/// Generates a Person XML Element, given a tuple.
let createPerson (id:string, name:string) = new XElement(XName.Get("Person"),
                                                new XAttribute(XName.Get("ID"), id),
                                                new XElement(XName.Get("Name"), name)
)

/// Filter People by having odd ID's
let oddFilter = fun (id:string, name:string) -> (System.Int32.Parse(id) % 2).Equals(1) 

/// Open filter which will return all people
let allFilter = fun (id:string, name:string) -> true

/// Generates a People XML Element.
let createPeople filter = new XElement(XName.Get("People"), 
                                ppl |> List.filter(filter)  |> List.map createPerson
)

/// First XML Object
let XmlA = createPeople oddFilter

/// Second XML Object
let XmlB = createPeople allFilter


printf "%A\n\n%A" XmlA XmlB


/// Waits for a keypress
let pauseKey = fun () -> System.Console.ReadKey() |> ignore


pauseKey()

Мои вопросы: Какие вещи я преуспел в этом сценарии? Какие части могли быть добиты большего успеха?

Я действительно с нетерпением жду некоторых идей, и я вполне взволнован тем, чтобы знакомиться с функциональными парадигмами также!:)

Заранее спасибо

12
задан Russell 3 March 2010 в 00:22
поделиться

4 ответа

В принципе, ваш код в порядке.

Есть только некоторые моменты, которые можно упростить с синтаксической точки зрения.

let ppl:(string * string) list = [
    ("1", "Jerry"); 
    ("2", "Max"); 
    ("3", "Andrew");
]

Компилятор может выводить большинство типов с помощью Сам:

let ppl = [ "1", "Jerry";
            "2", "Max";
            "3", "Andrew" ]

И, конечно, вы можете переписать свои фильтры, как это, благодаря каррированию :

let oddFilter (id:string, name:string) = (int id) % 2 = 1
let allFilter (id:string, name:string) = true

Самым большим улучшением будет отделение индексов от имен и предоставление возможности программе выполнять нумерацию. Вам не нужно работать со строками вместо чисел и можно использовать более идиоматические функции без кортежей:

let ppl = [ "Jerry"; "Max"; "Andrew" ]

let oddFilter id name = id % 2 = 1
let allFilter id name = true

let createPerson id name = ...

Часть

ppl |> List.filter(filter)  |> List.map createPerson

будет переписана на

[ for (index, name) in List.mapi (fun i x -> (i, x)) do
      if filter index name then
          yield createPerson (string index) name ]
13
ответ дан 2 December 2019 в 18:19
поделиться

Most of the time deforesting without a specific reason, generally performance, is a bad idea. Which one of these do you see as easier to read and less error prone? Deforesting taken out of context just adds complexity and/or coupling to your code.

let createPeople filter ppl =
    ppl 
    |> List.mapi (fun i x -> (i, x)) 
    |> List.filter filter
    |> List.map createPerson

let createPeople filter ppl =
    [ for (index, name) in ppl |> List.mapi (fun i x -> (i, x)) do
          if filter (index, name) then
              yield createPerson (index, string) ]

let createPeople filter ppl = 
    (ppl |> List.mapi (fun i x -> (i, x)), []) 
    ||> List.foldBack (fun P acc -> if filter P then (createPerson P)::acc else acc) 

Once you get used to the syntax function composition allows you to drop ppl.

let createPeople filter =
    List.mapi (fun i x -> (i, x)) 
    >> List.filter filter
    >> List.map createPerson

All of these use tupled data.

let filter (id, name) = 
    id % 2 = 1

let allFilter (id, name) = 
    true

let createPerson (id, name) = 
    ()
3
ответ дан 2 December 2019 в 18:19
поделиться
let createPeople filter = new XElement(XName.Get("People"), 
                            ppl |> List.filter(filter)  |> List.map createPerson
)

Эта часть может быть обезлесена вручную, или вы можете надеяться, что компилятор вырубит ее за вас.

По сути, есть промежуточная структура (список фильтрованных людей), которые, если это наивно скомпилировано, будут выделены для обслуживания только один раз. Лучше примените createPerson к каждому элементу, так как определено, входят они или нет, и напрямую построить окончательный результат.

РЕДАКТИРОВАТЬ: cfern внесла эту обезлесенную версию createPeople :

let createPeople filter = 
  new XElement(
    XName.Get("People"), 
    List.foldBack 
      (fun P acc -> if filter P then (createPerson P)::acc else acc) 
      ppl 
      [])

ПРИМЕЧАНИЕ: поскольку могут быть побочные эффекты в фильтре или createPerson , в F # это довольно сложно компилятор сам решает вырубить лес. В данном случае мне кажется, что вырубка леса является правильной, потому что даже если фильтр имеет побочные эффекты, createPerson не имеет, но я не специалист.

4
ответ дан 2 December 2019 в 18:19
поделиться

Мне также недавно потребовалось преобразовать XSL в файл XML. {{ 1}} Это F #, который я использовал для этого.

Есть некоторые интересные особенности использования методов .net.

(* Transforms an XML document given an XSLT. *)

open System.IO
open System.Text
open System.Xml
open System.Xml.Xsl

let path = @"C:\\XSL\\"

let file_xml = path + "test.xml"
let file_xsl = path + "xml-to-xhtml.xsl"

(* Compile XSL file to allow transforms *)
let compile_xsl (xsl_file:string) = new XslCompiledTransform() |> (fun compiled -> compiled.Load(xsl_file); compiled)
let load_xml (xml_file:string) = new XmlDocument() |> (fun doc -> doc.Load(xml_file); doc)

(* Transform an Xml document given an XSL (compiled *)
let transform (xsl_file:string) (xml_file:string) = 
      new MemoryStream()
        |> (fun mem -> (compile_xsl xsl_file).Transform((load_xml xml_file), new XmlTextWriter(mem, Encoding.UTF8)); mem)
        |> (fun mem -> mem.Position <- (int64)0; mem.ToArray())

(* Return an Xml fo document that has been transformed *)
transform file_xsl file_xml
    |> (fun bytes -> File.WriteAllBytes(path + "out.html", bytes))
0
ответ дан 2 December 2019 в 18:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: