作为一项功能性编程练习,我想我会写一个小程序来按照盈利能力对制作配方进行排序。
在OO语言中,我为每个食谱制作策略对象,使用Cost(),ExpectedRevenue()和Volume()作为成员。然后我将所有对象放在一个列表中,并按盈利/时间函数对它们进行排序。
尝试在F#中完成相同的结果,但我不确定如何去做。我有一些脱节的成本函数,例如:
let cPM (ss,marble) = (15.0 * ss + 10.0 * marble + 0.031) / 5.0
let cTRef (tear,clay) = (tear + 10.0 * clay + 0.031) / 5.0
然后是收入和数量定义,如:
let rPM = 1.05
let vPM = 50
但我不知道现在该做什么。列出看起来像
的元组(name: string, cost:double, revenue:double, volume:int)
然后对列表进行排序?感觉我错过了一些东西 - 仍然在OO中思考,更不用说以这种方式添加新的食谱会相当尴尬。
有没有人以更好的方式使用功能概念?看起来这种类型的计算问题非常适合功能风格。
非常感谢。
答案 0 :(得分:1)
在函数式语言中,您只能使用函数执行任何操作。在这里,您可以定义常用的盈利能力函数,并使用它List.sortBy
:
// recipe type with constants for Revenue, Volume and (ss,marble)
type recipe = {r: float; v: float; smth: float * float}
// list of recipes
let recipes = [
{r = 1.08; v = 47.0; smth = (28.0, 97.0)};
{r = 1.05; v = 50.0; smth = (34.0, 56.0)} ]
// cost function
let cPM (ss,marble) = (15.0 * ss + 10.0 * marble + 0.031) / 5.0
// profitability function with custom coefficients
let profitability recipe = recipe.r * 2.0 + recipe.v * 3.0 + cPM recipe.smth
// sort recipes by profitability
let sortedRecipes =
List.sortBy profitability recipes
// note: it's reordered now
printfn "%A" sortedRecipes
答案 1 :(得分:1)
接受的答案有点缺乏类型安全性,我认为 - 你已经说过FancySword是用金和钢制成的,所以你不必记得正确配对黄金数量和黄金价格!类型系统应该为您检查,并防止意外g * prices.Steel
错误。
如果修复了一组可能的资源类型,那么这对于度量单位来说是一个很好的用例。
[<Measure>] type Gold
[<Measure>] type Steel
[<Measure>] type FrogLegs
[<Measure>] type GameMoney
type Recipe = {
goldQty : float<Gold>
steelQty : float<Steel>
frogLegsQty : int<FrogLegs>
}
type Prices = {
goldPrice : float<GameMoney/Gold>
steelPrice : float<GameMoney/Steel>
frogLegsPrice : float<GameMoney/FrogLegs>
}
let recipeCost prices recipe =
prices.goldPrice * recipe.goldQty +
prices.steelPrice * recipe.steelQty +
// frog legs must be converted to float while preserving UoM
prices.frogLegsPrice * (recipe.frogLegsQty |> float |> LanguagePrimitives.FloatWithMeasure)
let currentPrices = {goldPrice = 100.0<GameMoney/Gold>; steelPrice = 50.0<GameMoney/Steel>; frogLegsPrice = 2.5<GameMoney/FrogLegs> }
let currentCost = recipeCost currentPrices
let fancySwordRecipe = {goldQty = 25.4<Gold>; steelQty = 76.4<Steel>; frogLegsQty = 0<FrogLegs>}
let fancySwordCost = currentCost fancySwordRecipe
编译器现在将确保检出所有计算。例如,在recipeCost
函数中,它确保总计为float<GameMoney>
。
由于您提到了卷,我认为您可以看到如何复制相同的模式来编写类型安全函数,这些函数将计算总配方卷作为int<InventoryVolume>
类型的值。