4
\$\begingroup\$

I have created a simple calculator that will assist in creating magic items from the tabletop RPG Pathfinder. Here are the full requirements, and if you want a more concise version, here is a player generated summary of the process.

I have been trying to get into F# and functional programming in general. I come from a strong object-oriented background and it has been difficult in ignoring those habits. Please focus on whether or not this is idiomatic F#. I would love to hear if there is a better way to write any of it. And, if you find bug, I'd be happy to know that too.

Questions

A couple of things specifically that I feel could be better would be the DC calculation. I wasn't sure how to approach applying the rush function only if the item was rushed. I also tried finding a place where I could apply functional composition, but I think I needed all the intermediate steps that I stop on.

Code

let baseDC casterLevel =
 5 + casterLevel
let rush dc =
 dc + 5
let ignoreRequirements requirements dc =
 dc + (5 * requirements)
let getBuildPrice basePrice =
 basePrice * 0.5
let getTime basePrice =
 floor (8.0 * basePrice / 1000.0)
let getMinBonusForNoCursed dc =
 dc - 6
let buildDaysWhileAdventuring isRushed buildTime =
 let adventuringBuildTime = buildTime / 4.0
 floor (if isRushed then adventuringBuildTime else adventuringBuildTime * 2.0)
[<EntryPoint>]
let main argv = 
 printfn "%A" argv
 let isRushed = true
 let casterLevel = 1
 let requirementsIgnored = 1
 let basePrice = 5000.0
 let buildPrice = getBuildPrice basePrice
 let buildTime = getTime basePrice
 let daysAdventuring = buildDaysWhileAdventuring isRushed buildTime
 let DC = 
 match isRushed with
 | false -> baseDC casterLevel |> ignoreRequirements requirementsIgnored
 | true -> baseDC casterLevel |> ignoreRequirements requirementsIgnored |> rush
 let minDC = getMinBonusForNoCursed DC
 printfn "Min/DC: %i/%i Cost: %.2f Days/Hours: %.1f/%.1f" minDC DC
 buildPrice daysAdventuring buildTime
 0 // Return code
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Apr 28, 2017 at 14:12
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I see a few problems with this, most notably, you have a plethora of magic numbers.

let baseDC casterLevel =
 5 + casterLevel
let rush dc =
 dc + 5
let ignoreRequirements requirements dc =
 dc + (5 * requirements)
let getBuildPrice basePrice =
 basePrice * 0.5
let getTime basePrice =
 floor (8.0 * basePrice / 1000.0)
let getMinBonusForNoCursed dc =
 dc - 6
let buildDaysWhileAdventuring isRushed buildTime =
 let adventuringBuildTime = buildTime / 4.0
 floor (if isRushed then adventuringBuildTime else adventuringBuildTime * 2.0)

In order, I see:

  1. 5 + casterLevel: what is 5?
  2. dc + 5: what is 5? Is it the same as #1?
  3. 5 * requirements: what is 5? Is it the same as #1 or #2?
  4. basePrice * 0.5: what is 0.5? Is it 1 / 2 or something different?
  5. 8.0 * basePrice: what is 8.0?
  6. #5 / 1000.0: what is 1000.0?
  7. dc - 6: what is 6?
  8. buildTime / 4.0: what is 4.0?
  9. adventuringBuildTime * 2.0: what is 2.0, is it 4.0 / 2, is it the 4.0 from #8 / 2?

For a functional program, it's not too bad. I don't like how many times you use if (I always prefer match), but when dealing with boolean types it does quite fine.

answered May 1, 2017 at 0:40
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.