aboutsummaryrefslogtreecommitdiff
path: root/src/fold.zig
blob: f967cdf836059a3972b2aa41a0e256363b1f127b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
const std = @import("std");
const typeVerify = @import("util.zig").typeVerify;

/// ```zig
/// (fn (fn (fn (b, a) b, b, []a) b)
/// ```
/// Folds a list of items over a function with the accumulator as the first arg
/// Type signature: `(b -> a -> b) -> b -> [a] -> b`
/// `func` is of type `b -> a -> b`, where `items` is of type `[a]` and `accumulator` is of type `b`.
pub fn foldl(
    comptime func: anytype,
    accumulator: (typeVerify(@TypeOf(func), .{ .@"fn" }).@"fn".params[0].type.?),
    items: ([]typeVerify(@TypeOf(func), .{ .@"fn" }).@"fn".params[1].type.?),
) typeVerify(@TypeOf(func), .{ .@"fn" }).@"fn".return_type.? {
    var accum_internal = accumulator;
    for(items) |i|
        accum_internal = func(accum_internal, i);
    return accum_internal;
}

/// ```zig
/// (fn (fn (fn (a, b) b, b, []a) b)
/// ```
/// Folds a list of items over a function with the accumulator as the second arg
/// Type signature: `(a -> b -> b) -> b -> [a] -> b`
/// `func` is of type `a -> b -> b`, where `items` is of type `[a]` and `accumulator` is of type `b`.
pub fn foldr(
    comptime func: anytype,
    accumulator: (typeVerify(@TypeOf(func), .{ .@"fn" }).@"fn".params[1].type.?),
    items: ([]typeVerify(@TypeOf(func), .{ .@"fn" }).@"fn".params[0].type.?),
) typeVerify(@TypeOf(func), .{ .@"fn" }).@"fn".return_type.? {
    var accum_internal = accumulator;
    for(items) |i|
        accum_internal = func(i, accum_internal);
    return accum_internal;
}

/// Variant of `foldl` where the first element is the base case
pub fn foldl1(
    comptime func: anytype,
    items: ([]typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".params[0].type.?)
) typeVerify(@TypeOf(func), .{ .@"fn" }).@"fn".return_type.? {
    return foldl(func, items[0], items);
}

/// Variant of `foldr` where the first element is the base case
pub fn foldr1(
    comptime func: anytype,
    items: ([]typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".params[0].type.?)
) typeVerify(@TypeOf(func), .{ .@"fn" }).@"fn".return_type.? {
    return foldr(func, items[0], items);
}

pub fn scanlAlloc(
    allocator: std.mem.Allocator,
    comptime func: anytype,
    base: (typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".params[0].type.?),
    items: ([]typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".params[1].type.?)
) ![]typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".return_type.? {
    var output = try allocator.alloc(typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".return_type.?, items.len);
    scanlBuffer(func, base, items, &output);
    return output;
}

pub fn scanlBuffer(
    comptime func: anytype,
    base: (typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".params[0].type.?),
    items: ([]typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".params[1].type.?),
    buffer: (*[]typeVerify(@TypeOf(func), .{.@"fn"}).@"fn".return_type.?),
) void {
    for (buffer.*, 0..) |*out, i|
        out.* = foldl(func, base, items[0..i+1]);
}