【发布时间】:2016-08-09 00:06:41
【问题描述】:
我正在尝试学习 F#,我觉得我可以编写/重写这段代码以使其更“惯用”F#,但我就是不知道如何完成它。
我的简单程序将从 2 个 csv 文件加载值:天际药水效果列表和天际成分列表。一种成分有 4 种效果。一旦我有了成分,我就可以编写一些东西来处理它们 - 现在,我只想以一种有意义的方式编写 CSV 负载。
代码
这是我的类型:
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
这里是我解析单个逗号分隔字符串的地方,每种类型:
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!"
所以我感觉我应该能够构建一个函数来接受这些函数之一或将它们链接起来或其他东西,这样我就可以递归地遍历 CSV 文件中的行并传递那些线到上面的正确功能。到目前为止,这是我尝试过的:
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"
但这(可以预见)在递归的第二个实例和最后一个模式上存在编译错误。具体来说,parsedLine :: parsedRest 第二次出现不会编译。这是因为该函数试图同时返回一个 Effect 和一个 Ingredient,这显然不会。
现在,我可以编写 2 个完全不同的函数来处理不同的 CSV,但这感觉像是额外的重复。这可能是一个比我认为的更难的问题,但感觉这应该是相当简单的。
来源
我从本书第 4 章中获取的 CSV 解析代码:https://www.manning.com/books/real-world-functional-programming
【问题讨论】:
-
您想自己实现还是只是在寻找解决方案?最快的方法就是使用CSV Type Provider。您不需要定义枚举,只需将 Effect 和 Ingredient 包装到 CsvType 中即可。
标签: csv parsing f# encapsulation