Skip to content

Commit

Permalink
Add some initial examples
Browse files Browse the repository at this point in the history
  • Loading branch information
sharkdp authored and David Peter committed May 16, 2024
1 parent 37bfcdb commit d5f24ef
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 4 deletions.
52 changes: 52 additions & 0 deletions numbat/modules/core/lists.nbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,55 @@
use core::scalar

fn len<A>(xs: List<A>) -> Scalar
fn head<A>(xs: List<A>) -> A
fn tail<A>(xs: List<A>) -> List<A>
fn cons<A>(x: A, xs: List<A>) -> List<A>

fn is_empty<A>(xs: List<A>) -> Bool = len(xs) == 0

# We definitely want to make the following functions generic, but this is not yet possible:
# Also, we want the base case to be the empty list, but this is also not yet possible.

fn generate(n: Scalar, f: Fn[() -> Scalar]) -> List<Scalar> =
if n == 1
then [f()]
else cons(f(), generate(n - 1, f))

fn map(f: Fn[(Scalar) -> Scalar], xs: List<Scalar>) -> List<Scalar> =
if len(xs) == 1
then [f(head(xs))]
else cons(f(head(xs)), map(f, tail(xs)))

fn cons_end(xs: List<Scalar>, x: Scalar) -> List<Scalar> =
if is_empty(xs)
then [x]
else cons(head(xs), cons_end(tail(xs), x))

fn reverse(xs: List<Scalar>) -> List<Scalar> =
if len(xs) == 1
then xs
else cons_end(reverse(tail(xs)), head(xs))

fn sequence(n: Scalar) -> List<Scalar> =
if n == 1
then [0]
else cons_end(sequence(n - 1), n - 1)

fn foldl(f: Fn[(Scalar, Scalar) -> Scalar], acc: Scalar, xs: List<Scalar>) -> Scalar =
if len(xs) == 1
then f(acc, head(xs))
else foldl(f, f(acc, head(xs)), tail(xs))

fn const_5() -> Scalar = 5

fn inc(x: Scalar) -> Scalar = x + 1

fn add(x: Scalar, y: Scalar) -> Scalar = x + y
fn mul(x: Scalar, y: Scalar) -> Scalar = x * y

assert(sequence(5) == [0, 1, 2, 3, 4])
assert(generate(3, const_5) == [5, 5, 5])
assert(map(inc, [1, 2, 3]) == [2, 3, 4])
assert(reverse([1, 2, 3]) == [3, 2, 1])
assert(foldl(add, 0, [1, 2, 3, 4, 5]) == 15)
assert(foldl(mul, 1, [1, 2, 3, 4, 5]) == 120)
16 changes: 16 additions & 0 deletions numbat/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,14 @@ pub(crate) fn functions() -> &'static HashMap<String, ForeignFunction> {
},
);

m.insert(
"len".to_string(),
ForeignFunction {
name: "len".into(),
arity: 1..=1,
callable: Callable::Function(Box::new(len)),
},
);
m.insert(
"head".to_string(),
ForeignFunction {
Expand Down Expand Up @@ -864,6 +872,14 @@ fn exchange_rate(args: &[Value]) -> Result<Value> {
)))
}

fn len(args: &[Value]) -> Result<Value> {
assert!(args.len() == 1);

let list = args[0].unsafe_as_list();

Ok(Value::Quantity(Quantity::from_scalar(list.len() as f64)))
}

fn head(args: &[Value]) -> Result<Value> {
assert!(args.len() == 1);

Expand Down
9 changes: 5 additions & 4 deletions numbat/src/typed_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ impl std::fmt::Display for Type {
impl PrettyPrint for Type {
fn pretty_print(&self) -> Markup {
match self {
Type::Never => m::keyword("!"),
Type::Never => m::type_identifier("!"),
Type::Dimension(d) => d.pretty_print(),
Type::Boolean => m::keyword("Bool"),
Type::String => m::keyword("String"),
Type::DateTime => m::keyword("DateTime"),
Type::Boolean => m::type_identifier("Bool"),
Type::String => m::type_identifier("String"),
Type::DateTime => m::type_identifier("DateTime"),
Type::Fn(param_types, return_type) => {
m::type_identifier("Fn")
+ m::operator("[(")
Expand Down Expand Up @@ -164,6 +164,7 @@ impl Type {
match (self, other) {
(Type::Never, _) => true,
(_, Type::Never) => false,
(Type::List(el1), Type::List(el2)) => el1.is_subtype_of(el2),
(t1, t2) => t1 == t2,
}
}
Expand Down

0 comments on commit d5f24ef

Please sign in to comment.