功能编程练习

时间:2015-09-13 19:29:53

标签: f# functional-programming

作为一项功能性编程练习,我想我会写一个小程序来按照盈利能力对制作配方进行排序。

在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中思考,更不用说以这种方式添加新的食谱会相当尴尬。

有没有人以更好的方式使用功能概念?看起来这种类型的计算问题非常适合功能风格。

非常感谢。

2 个答案:

答案 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>类型的值。