Skip to content

Commit 9c62fef

Browse files
authored
feat(stdlib): Add higher order array functions (#833)
* Add higher order array functions * Fix new functions * Replace for-each loops with regular for loops: * Fix type errors * Remove redundant clone
1 parent ad5d889 commit 9c62fef

File tree

3 files changed

+75
-2
lines changed
  • crates
    • nargo/tests/test_data/higher-order-functions/src
    • noirc_frontend/src/hir/type_check
  • noir_stdlib/src

3 files changed

+75
-2
lines changed

crates/nargo/tests/test_data/higher-order-functions/src/main.nr

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use dep::std;
2+
13
fn main() -> pub Field {
24
let f = if 3 * 7 > 200 { foo } else { bar };
35
constrain f()[1] == 2;
@@ -22,8 +24,26 @@ fn main() -> pub Field {
2224
x = x + 1;
2325
constrain (|y| y + z)(1) == 4;
2426
x = x + 1;
27+
let ret = twice(add1, 3);
28+
29+
test_array_functions();
30+
31+
ret
32+
}
33+
34+
/// Test the array functions in std::array
35+
fn test_array_functions() {
36+
let myarray: [i32; 3] = [1, 2, 3];
37+
constrain std::array::any(myarray, |n| n > 2);
38+
39+
let evens: [i32; 3] = [2, 4, 6];
40+
constrain std::array::all(evens, |n| n > 1);
2541

26-
twice(add1, 3)
42+
constrain std::array::fold(evens, 0, |a, b| a + b) == 12;
43+
constrain std::array::reduce(evens, |a, b| a + b) == 12;
44+
45+
let descending = std::array::sort_via(myarray, |a, b| a > b);
46+
constrain descending == [3, 2, 1];
2747
}
2848

2949
fn foo() -> [u32; 2] {

crates/noirc_frontend/src/hir/type_check/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ pub fn comparator_operand_type_rules(
741741

742742
let comptime = CompTime::No(None);
743743
if other.try_bind_to_polymorphic_int(var, &comptime, true, op.location.span).is_ok() || other == &Type::Error {
744-
Ok(other.clone())
744+
Ok(Bool(comptime))
745745
} else {
746746
Err(format!("Types in a binary operation should match, but found {lhs_type} and {rhs_type}"))
747747
}

noir_stdlib/src/array.nr

+53
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,56 @@ fn len<T>(_input : [T]) -> comptime Field {}
33

44
#[builtin(arraysort)]
55
fn sort<T, N>(_a: [T; N]) -> [T; N] {}
6+
7+
// Sort with a custom sorting function.
8+
fn sort_via<T, N>(mut a: [T; N], ordering: fn(T, T) -> bool) -> [T; N] {
9+
for i in 1..len(a) {
10+
for j in 0..i {
11+
if ordering(a[i], a[j]) {
12+
let old_a_j = a[j];
13+
a[j] = a[i];
14+
a[i] = old_a_j;
15+
}
16+
}
17+
}
18+
a
19+
}
20+
21+
// Apply a function to each element of the array and an accumulator value,
22+
// returning the final accumulated value. This function is also sometimes
23+
// called `foldl`, `fold_left`, `reduce`, or `inject`.
24+
fn fold<T, U, N>(array: [T; N], mut accumulator: U, f: fn(U, T) -> U) -> U {
25+
for i in 0 .. len(array) {
26+
accumulator = f(accumulator, array[i]);
27+
}
28+
accumulator
29+
}
30+
31+
// Apply a function to each element of the array and an accumulator value,
32+
// returning the final accumulated value. Unlike fold, reduce uses the first
33+
// element of the given array as its starting accumulator value.
34+
fn reduce<T, N>(array: [T; N], f: fn(T, T) -> T) -> T {
35+
let mut accumulator = array[0];
36+
for i in 1 .. len(array) {
37+
accumulator = f(accumulator, array[i]);
38+
}
39+
accumulator
40+
}
41+
42+
// Returns true if all elements in the array satisfy the predicate
43+
fn all<T, N>(array: [T; N], predicate: fn(T) -> bool) -> bool {
44+
let mut ret = true;
45+
for i in 0 .. len(array) {
46+
ret &= predicate(array[i]);
47+
}
48+
ret
49+
}
50+
51+
// Returns true if any element in the array satisfies the predicate
52+
fn any<T, N>(array: [T; N], predicate: fn(T) -> bool) -> bool {
53+
let mut ret = false;
54+
for i in 0 .. len(array) {
55+
ret |= predicate(array[i]);
56+
}
57+
ret
58+
}

0 commit comments

Comments
 (0)