Skip to content
Varlig Guide
Varlig home

Your own functions

When you type the same formula again and again with different numbers, turn it into a function. You name the formula and its inputs once, then call it wherever you need an answer: a tip calculator, a BMI check, a savings projection or an invoice.

This page covers defining and calling functions, how they use the other names in your note, conditions and recursion, and the limits that apply. For the functions that come with Varlig, such as sqrt and round, see the built-in function reference.

Defining and calling a function

Write the function’s name, its parameters in parentheses, an equals sign and the formula. Then call it with values in the same order:

calc
tip(bill, pct) = bill * pct
tip($48, 15%) gives $7.20
tip($120, 12.5%) gives $15.00
tip($36 + $12, 15%) gives $7.20

The definition line shows no answer. Each call puts your values in place of bill and pct and works out the formula. An argument can be a whole calculation, like $36 + $12 above.

Arguments are full values, not only numbers, so units and currencies carry through the formula:

calc
bmi(weight, height) = weight / height^2
bmi(81 kg, 1.8 m) gives 25 kg/m²

Units are kept as you give them, so bmi(81 kg, 180 cm) answers in kg/cm². To get the same unit whatever you pass in, convert inside the function:

calc
bmi(weight, height) = (weight / height^2) in kg/m^2
bmi(81 kg, 180 cm) gives 25 kg/m²
bmi(80 kg, 5.9 ft) gives 24.7375131668 kg/m²

A function can also have no parameters. Write empty parentheses both when you define it and when you call it:

calc
standard_vat() = 20%
£120 * standard_vat() gives £24.00

A plain variable, such as standard_vat = 20%, usually does the same job with less typing.

Names and parameters

  • Function and parameter names are single words. Use letters, digits and underscores, such as net_pay or bmi2, with no spaces. If you write area of circle(r) = pi * r^2, the line suggests the name to use instead: area_of_circle.
  • Function names ignore case: after defining Tip(bill, pct), you can call tip($48, 15%).
  • Each parameter needs its own name. f(a, a) = a is an error.
  • A function can have up to 32 parameters.
  • You can’t reuse the name of a built-in function. round(x) = … or sqrt(x) = … shows an error instead of replacing it. A plain variable can still use one of those names, such as floor = 12 m²; see Names.
  • The spreadsheet spellings avg, total and stdev are free to use. Define your own total(order) and your version is the one that runs.
  • A function and a variable can share a name. rate reads the variable and rate(5) calls the function.
  • Always call a function with parentheses. A function name on its own, with no variable of the same name, shows an error.

Commas in arguments

A comma followed by a space separates the arguments, and a comma followed by exactly three digits groups thousands, so you can write amounts the way you normally would:

calc
tip(bill, pct) = bill * pct
tip($1,200, 15%) gives $180.00
tip($1200,15%) gives $180.00

When a function needs more values than the spaces give it, every comma separates, as in the second call. Use a decimal point for fractions, as in tip($48, 12.5%).

Using other names in your note

A function can use variables from your note. It reads their current value each time you call it:

calc
vat = 20%
with_vat(price) = price * (1 + vat)
with_vat(£50) gives £60.00
vat = 5%
with_vat(£50) gives £52.50

The variable must already exist when you define the function, so put vat = 20% above with_vat. If it doesn’t exist yet, the definition line shows an error.

Parameters are local to the function. A parameter called price doesn’t read or change a variable called price elsewhere in the note:

calc
price = £10
double(price) = price * 2
double(£3) gives £6.00
price gives £10.00

Like variables, a function defined in one calc block can be used in later calc blocks in the same note. Varlig works through the note from top to bottom, so define a function above the first line that calls it. A call above the definition shows no answer.

Functions that call other functions

Small functions can build on each other:

calc
day_rate = £400
fee(days) = days * day_rate
invoice(days) = fee(days) * 1.2
invoice(5) gives £2,400.00

A function remembers the version of a helper that existed when you defined it. If you define the same helper again further down, functions defined earlier keep using the old version:

calc
shipping(order) = £4.95
total(order) = order + shipping(order)
shipping(order) = £2.95
total(£30) gives £34.95
shipping(£30) gives £2.95

To pick up the new shipping, define total again below it. Editing a definition in place doesn’t cause this. Varlig recalculates the note from the top, so everything below uses your edited version.

A function can also call a helper you define further down. It then uses whatever that helper is when you make the call, so the helper must exist by the time you call the outer function:

calc
checkout(order) = order + delivery(order)
delivery(order) = if order >= £40 then £0 else £3.50
checkout(£25) gives £28.50
checkout(£60) gives £60.00

Conditions

Use if … then … else … to choose between results. Chain another if after else for more than two cases:

calc
postage(weight) = if weight <= 100 g then £0.85 else if weight <= 750 g then £1.55 else £3.20
postage(90 g) gives £0.85
postage(500 g) gives £1.55
postage(1.2 kg) gives £3.20

Only the branch that applies is worked out. That lets you guard against a calculation that would otherwise fail, such as dividing by zero:

calc
per_person(total, people) = if people > 0 then total / people else £0
per_person(£90, 3) gives £30.00
per_person(£90, 0) gives £0.00

Recursion

A function can call itself, as long as a condition eventually stops it. This one counts the handshakes when everyone in a group shakes hands once:

calc
handshakes(people) = if people <= 1 then 0 else (people - 1) + handshakes(people - 1)
handshakes(6) gives 15
handshakes(10) gives 45

Each call nests one level deeper, and at most 16 nested calls are allowed. handshakes(16) still works, but handshakes(17) shows Error: calculation limit. A function that never reaches its stopping case is accepted when you define it, and hits the same limit when you call it. Two functions can also call each other, within the same limit.

For everyday counting, the built-in functions are quicker and have no such limit. combination(10, 2) also gives 45, and factorial(n), or n!, covers the classic recursive example.

Lists, matrices and more

Arguments can be lists, matrices or complex numbers, and a body can use any built-in function:

calc
spread(scores) = max(scores) - min(scores)
spread([12, 18, 9, 21]) gives 12

A body can also contain a summation or an equation solver with its own local variable. See Lists and statistics and Summation, equation solving and calculus.

Pitfalls

  • Write powers with ^. isn’t accepted inside a function. Worse, a short parameter name can match a unit: in w / h², the means square hours, not the parameter h. Write w / h^2.
  • Check the number of arguments. Calling tip($48) when the function expects two values shows an error.
  • One line, one formula. A definition is a single expression on one line. For a calculation with several steps, define a small function for each step and combine them.
  • A broken redefinition keeps the old version. If a new definition of tip has a mistake, the line shows an error and the previous working tip stays available.
  • Answers can change when the note recalculates. Calls are worked out again each time, so a function that uses random or today’s date can give a new answer.
  • Errors come through. If an argument makes the formula fail, such as dividing by zero, the call shows that error.

Limits

What Limit
Parameters per function 32
Nested calls (a function calling itself or another) 16
Calls made while working out one top-level call 16,384
Functions defined in a note 1,024

Hitting a limit shows Error: calculation limit. The rest of the note keeps working. See Errors, diagnostics and limits for every limit.

Putting it together

Here is a freelance invoice. The rate and VAT sit at the top as named values, and three small functions do the work:

calc
# March invoice
day_rate = £450
vat = 20%
fee(days) = days * day_rate
with_vat(amount) = amount * (1 + vat)
late_fee(amount, days_late) = if days_late > 30 then amount * 2% else £0
design = fee(8) gives £3,600.00
build = fee(4.5) gives £2,025.00
subtotal = design + build gives £5,625.00
with_vat(subtotal) gives £6,750.00
late_fee(with_vat(subtotal), 45) gives £135.00

Change day_rate or vat and every line below updates. When the client pays late, one call adds the fee.