DTL
1.x
Docs/DTL/Standard library
Open

Reading6 min
Updated2 Aug 2026
Sourcev1/standard-library.mdx

Standard library

Five namespaces ship preloaded. Every one of them is written in DTL, which is the honest test of whether the language is expressive enough to be worth embedding.

None of them reaches outside the interpreter. Anything that does is a builtin the host registered.

system::math01

fn clamp(value: float, min: float, max: float) -> float =>
    if value < min then min else if value > max then max else value

fn lerp(a: float, b: float, t: float) -> float =>
    a + (b - a) * t

fn normalize(value: float, min: float, max: float) -> float =>
    if max == min then 0.0 else (value - min) / (max - min)

fn moving_avg(values: float[], window: int) -> float =>
    values | tail(window) | avg()

fn ewma(values: float[], alpha: float = 0.3) -> float:
    values | reduce(values | first(), (acc, v) => alpha * v + (1 - alpha) * acc)

system::text02

fn slugify(text: string) -> string =>
    text | lower() | trim() | replace(" ", "-") | replace("[^a-z0-9-]", "")

fn truncate(text: string, max_len: int, suffix: string = "...") -> string =>
    if text | len() <= max_len then text
    else (text | substr(0, max_len - (suffix | len()))) ++ suffix

fn extract_number(text: string) -> float =>
    text | match_regex("[0-9]+\\.?[0-9]*") | first() | as_float()

system::datetime03

fn business_days_between(start: datetime, end: datetime) -> int:
    let days = start | diff(end, "days") | as_int()
    let weeks = days / 7
    let remaining = days % 7
    weeks * 5 + (remaining | clamp(0, 5))

fn is_business_day(dt: datetime) -> bool =>
    dt | day_of_week() >= 1 && dt | day_of_week() <= 5

fn time_bucket(dt: datetime, interval: string) -> datetime =>
    dt | start_of(interval)

system::stats04

fn z_score(value: float, values: float[]) -> float:
    let mean = values | avg()
    let std = values | stdev()
    if std == 0 then 0.0
    else (value - mean) / std

fn outlier_bounds(values: float[], factor: float = 1.5) -> object:
    let q1 = values | percentile(25)
    let q3 = values | percentile(75)
    let iqr = q3 - q1
    return { lower: q1 - factor * iqr, upper: q3 + factor * iqr }

fn correlation(x: float[], y: float[]) -> float:
    let n = x | count()
    let sum_xy = x | zip(y) | map((a, b) => a * b) | sum()
    let sum_x = x | sum()
    let sum_y = y | sum()
    let sum_x2 = x | map(v => v * v) | sum()
    let sum_y2 = y | map(v => v * v) | sum()
    (n * sum_xy - sum_x * sum_y) /
        sqrt((n * sum_x2 - sum_x * sum_x) * (n * sum_y2 - sum_y * sum_y))

system::collections05

fn top_n(values: any[], n: int, key: string = "") -> any[]:
    if key == "" then values | sort(desc) | head(n)
    else values | sort_by(key, desc) | head(n)

fn histogram(values: float[], bins: int = 10) -> object[]:
    let min_val = values | min()
    let max_val = values | max()
    let bin_width = (max_val - min_val) / bins
    values
        | map(v => ((v - min_val) / bin_width) | floor() | clamp(0, bins - 1) | as_int())
        | group_by(bin => bin)
        | map((bin, items) => {
            bin: bin,
            range_start: min_val + bin * bin_width,
            range_end: min_val + (bin + 1) * bin_width,
            count: items | count()
          })