Functions
Functions have two types of parameters:
- Positional parameters, which require an argument.
- Named parameters, which optionally take an argument, otherwise using their default value.
So this function is named fahrenheit_to_celsius
and has one parameter temp
:
PRQL
let fahrenheit_to_celsius = temp -> (temp - 32) / 1.8
from cities
derive temp_c = (fahrenheit_to_celsius temp_f)
SQL
SELECT
*,
(temp_f - 32) / 1.8 AS temp_c
FROM
cities
This function is named interp
, and has two positional parameters named high
and x
, and one named parameter named low
which takes a default argument of 0
. It calculates the proportion of the distance that x
is between low
and high
.
PRQL
let interp = low:0 high x -> (x - low) / (high - low)
from students
derive {
sat_proportion_1 = (interp 1600 sat_score),
sat_proportion_2 = (interp low:0 1600 sat_score),
}
SQL
SELECT
*,
(sat_score - 0) / (1600 - 0) AS sat_proportion_1,
(sat_score - 0) / (1600 - 0) AS sat_proportion_2
FROM
students
Other examples
PRQL
let is_adult = col -> col >= 18
let writes_code = col -> (col | in ["PRQL", "Rust"])
let square = col -> (col | math.pow 2)
let starts_with_a = col -> (col | text.lower | text.starts_with("a"))
from employees
select {
first_name,
last_name,
hobby,
adult = is_adult age,
age_squared = square age,
}
filter ((starts_with_a last_name) && (writes_code hobby))
SQL
WITH table_0 AS (
SELECT
first_name,
last_name,
hobby,
age >= 18 AS adult,
POW(age, 2) AS age_squared
FROM
employees
)
SELECT
first_name,
last_name,
hobby,
adult,
age_squared
FROM
table_0
WHERE
LOWER(last_name) LIKE CONCAT('a', '%')
AND hobby IN ('PRQL', 'Rust')
Piping values into functions
Consistent with the principles of PRQL, it’s possible to pipe values into functions, which makes composing many functions more readable. When piping a value into a function, the value is passed as an argument to the final positional parameter of the function. Here’s the same result as the examples above with an alternative construction:
PRQL
let interp = low:0 high x -> (x - low) / (high - low)
from students
derive {
sat_proportion_1 = (sat_score | interp 1600),
sat_proportion_2 = (sat_score | interp low:0 1600),
}
SQL
SELECT
*,
(sat_score - 0) / (1600 - 0) AS sat_proportion_1,
(sat_score - 0) / (1600 - 0) AS sat_proportion_2
FROM
students
and
PRQL
let fahrenheit_to_celsius = temp -> (temp - 32) / 1.8
from cities
derive temp_c = (temp_f | fahrenheit_to_celsius)
SQL
SELECT
*,
(temp_f - 32) / 1.8 AS temp_c
FROM
cities
We can combine a chain of functions, which makes logic more readable:
PRQL
let fahrenheit_to_celsius = temp -> (temp - 32) / 1.8
let interp = low:0 high x -> (x - low) / (high - low)
from kettles
derive boiling_proportion = (temp_c | fahrenheit_to_celsius | interp 100)
SQL
SELECT
*,
((temp_c - 32) / 1.8 - 0) / (100 - 0) AS boiling_proportion
FROM
kettles
Late binding
Functions can bind to any variable that is in scope when the function is executed. For example, here cost_total
refers to the column that’s introduced in the from
.
PRQL
let cost_share = cost -> cost / cost_total
from costs
select {materials, labor, overhead, cost_total}
derive {
materials_share = (cost_share materials),
labor_share = (cost_share labor),
overhead_share = (cost_share overhead),
}
SQL
SELECT
materials,
labor,
overhead,
cost_total,
materials / cost_total AS materials_share,
labor / cost_total AS labor_share,
overhead / cost_total AS overhead_share
FROM
costs