← All examples

Shop

shop.zg
interface Priced <T> {
    fn price [lent 'x': <T>] -> int32;
}

enum Stock {
    out,
    few: int32,
    plenty
}

struct Item {
    name: str.utf8,
    cents: int32[min 0, max 100_000],
    stock: Stock
}

fn price [lent 'i': Item] -> int32 { return 'i'.cents; }

fn cheapest <T: Priced> [lent 'xs': list[<T>]] -> <T> or fail[empty] {
    if list.length[lend 'xs'] equal_to 0 { fail empty; }
    let 'best' := 1;
    for 'k' from 2 to list.length[lend 'xs'] by 1 {
        if price[lend 'xs'[pos 'k']] < price[lend 'xs'[pos 'best']] { change 'best' = 'k'; }
    }
    return copy 'xs'[pos 'best'];
}

fn describe [lent 'i': Item] -> str.utf8 {
    let 'dollars' := to.stored.str.utf8['i'.cents div.floor 100] ++ "." ++ to.stored.str.utf8['i'.cents mod.floor 100];
    match 'i'.stock {
        out      { return 'i'.name ++ " — sold out"; }
        few 'n'  { return 'i'.name ++ " — only " ++ to.stored.str.utf8['n'] ++ " left at $" ++ 'dollars'; }
        plenty   { return 'i'.name ++ " — $" ++ 'dollars'; }
    }
}

fn keep [lent 'xs': list[Item], 'test': fn[lent Item] -> bool] -> list[Item] {
    let 'out': list[Item] = [];
    for 'x' in lend 'xs' { if 'test'[lend 'x'] { list.append[lend.mut 'out', value copy 'x']; } }
    return give 'out';
}

MAIN {
    let 'shelf' := [
        Item[name = "rope",   cents = 1_250, stock = Stock.plenty],
        Item[name = "helmet", cents = 8_999, stock = Stock.few[2]],
        Item[name = "torch",  cents = 450,   stock = Stock.out]
    ];
    for 'i' in lend 'shelf' { std::print.stored[describe[lend 'i'], newln]; }

    let 'limit' := 5_000;
    let 'affordable' := keep[lend 'shelf', fn [lent 'i': Item] -> bool with [lend 'limit'] { return 'i'.cents at_most 'limit'; }];
    std::print.useful[list.length[lend 'affordable'], " affordable", newln];

    let 'pick' := cheapest[lend 'affordable'] otherwise std::exit[0];
    std::print.stored["cheapest: ", 'pick'.name, newln];

    let 'text' := std::input.line[] otherwise str.empty;
    let 'budget' := to.int32[min 0, max 100_000]['text'] otherwise {
        not_a_number { std::print.stored["no budget given", newln]; std::exit[0]; }
        out_of_range { std::print.stored["budget must be 0..100000 cents", newln]; std::exit[1]; }
    };
    std::print.useful["budget ok: ", 'budget', newln];
}
Output
rope — $12.50
helmet — only 2 left at $89.99
torch — sold out
2 affordable
cheapest: torch
no budget given