Ich versuche, F # zu lernen, und ich fühle mich wie ich diesen Codeblock schreiben/umschreiben kann, um "idiomatischer" F # zu sein, aber ich kann einfach nicht herausfinden, wie ich es erreichen kann.Pass-Funktion, um doppelten Code zu reduzieren
Mein einfaches Programm lädt Werte aus 2 CSV-Dateien: Eine Liste der Skyrim-Trank-Effekte und eine Liste der Skyrim-Zutaten. Eine Zutat hat 4 Effekte. Sobald ich die Zutaten habe, kann ich etwas schreiben, um sie zu verarbeiten - im Moment möchte ich nur die CSV-Ladung in einer Weise schreiben, die Sinn macht.
-Code
Hier sind meine Typen:
type Effect(name:string, id, description, base_cost, base_mag, base_dur, gold_value) =
member this.Name = name
member this.Id = id
member this.Description = description
member this.Base_Cost = base_cost
member this.Base_Mag = base_mag
member this.Base_Dur = base_dur
member this.GoldValue = gold_value
type Ingredient(name:string, id, primary, secondary, tertiary, quaternary, weight, value) =
member this.Name = name
member this.Id = id
member this.Primary = primary
member this.Secondary = secondary
member this.Tertiary = tertiary
member this.Quaternary = quaternary
member this.Weight = weight
member this.Value = value
Hier ist, wo ich eine einzelne kommagetrennte Zeichenfolge analysieren, pro Typ:
let convertEffectDataRow (csvLine:string) =
let cells = List.ofSeq(csvLine.Split(','))
match cells with
| name::id::effect::cost::mag::dur::value::_ ->
let effect = new Effect(name, id, effect, Decimal.Parse(cost), Int32.Parse(mag), Int32.Parse(dur), Int32.Parse(value))
Success effect
| _ -> Failure "Incorrect data format!"
let convertIngredientDataRow (csvLine:string) =
let cells = List.ofSeq(csvLine.Split(','))
match cells with
| name::id::primary::secondary::tertiary::quaternary::weight::value::_ ->
Success (new Ingredient(name, id, primary, secondary, tertiary, quaternary, Decimal.Parse(weight), Int32.Parse(value)))
| _ -> Failure "Incorrect data format!"
So Ich fühle mich Ich sollte in der Lage sein, eine Funktion zu bauen, die eine dieser Funktionen akzeptiert oder sie kettet hing, damit ich rekursiv die Zeilen in der CSV-Datei durchgehen und diese Zeilen an die oben angegebene Funktion übergeben kann. Hier ist, was ich versucht habe, so weit:
type csvTypeEnum = effect=1 | ingredient=2
let rec ProcessStuff lines (csvType:csvTypeEnum) =
match csvType, lines with
| csvTypeEnum.effect, [] -> []
| csvTypeEnum.effect, currentLine::remaining ->
let parsedLine = convertEffectDataRow2 currentLine
let parsedRest = ProcessStuff remaining csvType
parsedLine :: parsedRest
| csvTypeEnum.ingredient, [] -> []
| csvTypeEnum.ingredient, currentLine::remaining ->
let parsedLine = convertIngredientDataRow2 currentLine
let parsedRest = ProcessStuff remaining csvType
parsedLine :: parsedRest
| _, _ -> Failure "Error in pattern matching"
Aber diese (vorhersagbar) hat einen Compiler-Fehler auf der zweiten Instanz von Rekursion und das letzte Muster. Genauer gesagt, das zweite Mal parsedLine :: parsedRest
zeigt sich nicht kompilieren. Dies liegt daran, dass die Funktion versucht, sowohl Effect
als auch Ingredient
zurückzugeben, was offensichtlich nicht funktioniert.
Jetzt könnte ich nur 2 völlig verschiedene Funktionen schreiben, um die verschiedenen CSVs zu behandeln, aber das fühlt sich an wie doppelte Vervielfältigung. Diese könnte ein härteres Problem sein, als ich es Kredit gebe, aber es fühlt sich an, als sollte das ziemlich direkt sein.
Quellen
Der Code CSV-Parsing ich aus Kapitel 4 dieses Buches nahm: https://www.manning.com/books/real-world-functional-programming
Sie
Möchten Sie dies selbst implementieren oder suchen Sie nur nach einer Lösung? Der schnellste Weg wäre, den [CSV Type Provider] (http://fsharp.github.io/FSharp.Data/library/CsvProvider.html) zu verwenden. Sie sollten keine Enumeration definieren müssen, sondern nur Effekt und Inhaltsstoff in CsvType einbinden. – s952163