As a functional programming exercise, I thought I'd write a little program to rank crafting recipes in an mmo by profitability.
In an OO language, I'd make strategy objects for each recipe, with Cost(), ExpectedRevenue(), and Volume() as members. I'd then put all the objects in a list and sort them by a profitability/time function.
Trying to accomplish the same result in F#, but I'm not certain how to go about it. I have some disjointed cost functions, for example:
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
and then revenue and volume definitions like:
let rPM = 1.05
let vPM = 50
but I'm not sure what to do now. Make a list of tuples that look like
(name: string, cost:double, revenue:double, volume:int)
and then sort the list? It feels like I'm missing something- still thinking in OO, not to mention adding new recipes in this fashion will be rather awkward.
Has anyone any tips to use the functional concepts in a better way? It seemed like this type of calculation problem would be a good fit for the functional style.
Much appreciated.
This is a fairly complex question with multiple possible answers. Also, it is quite hard to guess anything about your domain (I don't know what game you're playing :-)), so I'll try to make something up, based on the example.
The basic functional approach would be to model the different recipes using a discriminated union.
type Recipe =
| FancySword of gold:float * steel:float // Sword can be created from gold & steel
| MagicalStone of frogLegs:float // Magical stone requires some number of frog legs
Also, we need to know the prices of things in the game:
type Prices = { Gold : float; Steel : float; FrogLegs : float }
Now you can write functions to calculate the cost and expected revenue of the recipes:
let cost prices recipe =
match recipe with
| FancySword(g, s) ->
// To create a sword, we need 2 pieces of gold and 15 pieces of steel
2.0 * g * prices.Gold + s * 15.0 * prices.Steel
| MagicalStone(l) -> l * prices.FrogLeg
This takes the record with all the prices and it takes a recipe that you want to evaluate.
The example should give you some idea - starting with a discriminated union to model the problem domain (different recipes) and then writing a function with pattern matching in it is usually a good way to get started - but it's hard to say more with the limited information in your question.
In functional languages you can do anything only with functions. Here you can define common profitability function and sort your recipes with it and 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
The accepted answer is a little lacking in type safety, I think - you already stated that a FancySword is made of gold and steel, so you shouldn't have to remember to correctly pair the gold quantity with the gold price! The type system ought to check that for you, and prevent an accidental g * prices.Steel mistake.
If the set of possible resource types is fixed, then this is a nice use-case for Units of Measure.
[<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
The compiler will now ensure that all calculations check out. In the recipeCost function, for example, it ensures that the total is a float<GameMoney>.
Since you mentioned volume, I think you can see how you can replicate the same pattern to write type-safe functions that will calculate total recipe volumes as a value of type int<InventoryVolume>.
Related
I store various formulas in Postgres and I want to use those formulas in my code. It would look something like this:
var amount = 100;
var formula = '5/105'; // normally something I would fetch from Postgres
var total = amount * formula; // should return 4.76
Is there a way to evaluate the string in this manner?
As far as I'm aware, there isn't a formula solver package developed for Dart yet. (If one exists or gets created after this post, we can edit it into the answer.)
EDIT: Mattia in the comments points out the math_expressions package, which looks pretty robust and easy to use.
There is a way to execute arbitrary Dart code as a string, but it has several problems. A] It's very roundabout and convoluted; B] it becomes a massive security issue; and C] it only works if the Dart is compiled in JIT mode (so in Flutter this means it will only work in debug builds, not release builds).
So the answer is that unfortunately, you will have to implement it yourself. The good news is that, for simple 4-function arithmetic, this is pretty straight-forward, and you can follow a tutorial on writing a calculator app like this one to see how it's done.
Of course, if all your formulas only contain two terms with an operator between them like in your example snippet, it becomes even easier. You can do the whole thing in just a few lines of code:
void main() {
final amount = 100;
final formula = '5/105';
final pattern = RegExp(r'(\d+)([\/+*-])(\d+)');
final match = pattern.firstMatch(formula);
final value = process(num.parse(match[1]), match[2], num.parse(match[3]));
final total = amount * value;
print(total); // Prints: 4.761904761904762
}
num process(num a, String operator, num b) {
switch (operator) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}
throw ArgumentError(operator);
}
There are a few packages that can be used to accomplish this:
pub.dev/packages/function_tree
pub.dev/packages/math_expressions
pub.dev/packages/expressions
I used function_tree as follows:
double amount = 100.55;
String formula = '5/105*.5'; // From Postgres
final tax = amount * formula.interpret();
I haven't tried it, but using math_expressions it should look like this:
double amount = 100.55;
String formula = '5/105*.5'; // From Postgres
Parser p = Parser();
// Context is used to evaluate variables, can be empty in this case.
ContextModel cm = ContextModel();
Expression exp = p.parse(formula) * p.parse(amount.toString());
// or..
//Expression exp = p.parse(formula) * Number(amount);
double result = exp.evaluate(EvaluationType.REAL, cm);
// Result: 2.394047619047619
print('Result: ${result}');
Thanks to fkleon for the math_expressions help.
In some notes in my book they are deriving a composite function but I'm having trouble replicating it.
In particular, I am trying
g(y) = f(x^y) = f(h(y)) = f'(h(y))h'(y) = f'(x^y)(x_1-x_0)
but the f would be with respect to h not x so I'm not sure what I'm not seeing.
It looks like you are looking for: d/dy f(x^y).
Let's see how to evaluate that:
d/dy f(x^y)= f'(x^y) d/dy(x^y) = f'(x^y) x^y ln(x)
How to calculate d/dy(x^y)?
Notice that this is the elementary derivative:
'(a^x), which is a^x ln(a).
I would like to be able to express some Measure of a specific type in a variety of ways. This is a very wacky example.
If we are cooking Lamb, then we will need 3 tablespoons of olive oil, 1 cup of sugar, and 3 ounces of butter.
If we are cooking pie, then we will need 10 tablespoons of olive oil, and 1 ounce of salt
If we area cooking steak, then we will need 5 ounces of salt, 4 pounds of ice cream.
I have different measures:
[<Measure>] type Tablespoon
[<Measure>] type Ounce
[<Measure>] type Pounds
We also have the different foods we'd like to cook:
type Foods =
| Lamb
| Pie
| Steak
How do we create a record / function / something to represent the recipe above?
I'm attempting to model something like this:
What is the measure of the accompanying offerings? The accompanying
offering for a male or female sheep is an isaron12 of fine flour mixed
with a quarter of a hin13 of oil and a quarter of a hin of wine as a
wine libation. These are also [the accompanying offerings] for a goat
whether small14or large15 and whether male or female and for a ewe,
even if she is large. The accompanying offerings of a ram, however,
are two esronim mixed with a third of a hin of oil and a third of a
hin of wine as a libation. The accompanying offerings of a cow or a
calf, whether male or female, are three esronim mixed with a half of a
hin of oil and a half of a hin of wine as a libation.
Each accompanying offering is different depending on the animal being offered (sheep/goat/ram).
For your needs, I might not use F#'s units of measure system, and instead model your units as a discriminated union. The reason is because F#'s units of measure are treated as completely different types, so you can't write a list like [ 3.0<Tablespoon>; 0.5<Cup> ] as F# will throw a type error. But you could do something like the following:
type RecipeUnit =
| Tablespoon
| Cup
| Ounce
| Pound
type Ingredient =
| Butter
| OliveOil
| Sugar
| Salt
type RecipePart = { Amount: float
Unit: RecipeUnit
Item: Ingredient }
let pie = [
{ Amount = 10.0; Unit = Tablespoon; Item = OliveOil }
{ Amount = 1.0; Unit = Ounce; Item = Salt }
]
Or, to give an example with your actual data model:
type Unit =
| Isaron
| Hin
type Ingredient =
| Flour
| Oil
| Wine
type OfferingPart = { Amount: float
Unit: Unit
Item: Ingredient }
type Offering = OfferingPart list
let sheepOffering = [
{ Amount = 1.0; Unit = Isaron; Item = Flour }
{ Amount = 1.0 / 4.0; Unit = Hin; Item = Oil }
{ Amount = 1.0 / 4.0; Unit = Hin; Item = Wine }
]
let goatOffering = sheepOffering
let ramOffering = [
{ Amount = 2.0; Unit = Isaron; Item = Flour }
{ Amount = 1.0 / 3.0; Unit = Hin; Item = Oil }
{ Amount = 1.0 / 3.0; Unit = Hin; Item = Wine }
]
// Etc.
Note that 1.0 / 3.0 is imprecise; if that's a problem, you'll want to model rational fractions (as either a tuple or a 2-item record; I'll assume you don't need help with this one).
P.S. I assume that "esronim" is the plural of "isaron", and that the two esronim mentioned in the ram's offering are of flour. If I got that wrong, adjust my example accordingly.
i am new with f# , will be great if some 1 can help , nearly half a day gone solving this problem Thank you
module Certificate =
type T = {
Id: int
IsECert: bool
IsPrintCert: bool
CertifiedBy: string
Categories: Category.T list
}
let createPending now toZonedDateTime toBeCertifiedByName (job: Models.Job.T) (certificateType: Models.CertificateType.T) (pendingCertificate: Models.PendingCertificate.T) visualization (categories: Category.T list) =
let forCompletion = Models.PendingCertificate.getCertificateForCompletion pendingCertificate
{
Id = forCompletion.Id |> CertificateId.toInt
IsECert = Models.PendingCertificate.isECertificate pendingCertificate
IsPrintCert = Models.PendingCertificate.isPrintCertificate pendingCertificate
CertifiedBy = toBeCertifiedByName
Categories = categories}
i am getting an error in "Incomplete structured construct at or before this point"
Your formatting is all off. I will assume here that this is just a result of posting to StackOverflow, and your actual code is well indented.
The error comes from the definition of createPending: this function does not have a result. All its body consists of defining a forCompletion value, but there is nothing after it. Here's a simpler example that has the same problem:
let f x =
let y = 5
This function will produce the same error, because it also doesn't have a result. In F#, every function has to return something. The body cannot contain only definitions of helper functions or values. For example, I could fix my broken function above like this:
let f x =
let y = 5
x + y
This function first defines a helper value y, then adds it to its argument x, and returns the result.
> f 2
> 7
>
> f 0
> 5
How exactly you need to fix your function depends on what exactly you want it to mean. I can't help you here, because you haven't provided that information.
Hey guys let's say I have a function that gets that day's rate of how much something costs, by the pound, and multiplies it by how many pounds a customer wants. i.e
let convert_func (crab_rate, lobster_rate);
//and then on a certain day it is
let (crab_rate, lobster_rate) = convert_fun(3.4, 6.8); // $3.8 a pound for crab, $6.8 a pound for lobster.
// 10 being how many pounds i want.
crab_rate10 ;
Then my out put would be whatever 38 since ($3.8 * 10lbs) = $38
I tried doing if statements so that when the user just wants to find out the total cost of one thing and not both. But I keep getting errors. I can't figure out how to store the rate values in the parameters and then calling the function.
This is what i tried
let crab_rate (pound, rate) = (float pound) * rate;
let lobster_rate (pound, rate) = (float pound) * rate;
let convert_func (crab_rate, lobster_rate)= function (first,second ) ->
if crab_rate then (float pound) * rate;
elif lobster_rate (float pound) * rate;
let (crab_rate, lobster_rate) = convert_fun(3.4, 6.8); // $3.8 a pound for crab, $6.8 a pound for lobster.
// 10 being how many pounds i want.
crab_rate10 ;
I think you should start by making a general function for converting a cost/weight and a weight into a cost. In F#, you can even use units of measure to help you:
[<Measure>] type USD // Unit of measure: US Dollars
[<Measure>] type lb // Unit of measure: lbs
let priceForWeight rate (weight : float<lb>) : float<USD> =
rate * weight
The nice thing about functional languages with curried arguments is that we can easily use partial function application. That means when we have a function that has two arguments, we can choose to supply just one argument and get back a new function from that one remaining argument to the result.
We can therefore define a further pair of functions that use this priceForWeight function.
let crabPriceForWeight weight = priceForWeight 3.8<USD/lb> weight
let lobsterPriceForWeight weight = priceForWeight 6.8<USD/lb> weight
Notice that we've used our original function to define two new functions with fixed rates.
We can then evaluate it like this:
let crabPrice10 = crabPriceForWeight 10.0<lb> // result 38.0<USD>
Of course, you can also define a function that returns both prices together as a tuple for a supplied weight:
let crabAndLobsterPriceForWeight weight =
crabPriceForWeight weight, lobsterPriceForWeight weight