edt-xx / pipes

Pipes similar to CMS Pipelines for Zig
MIT License
6 stars 0 forks source link

FizzBuzz implementation #1

Open gwenzek opened 3 years ago

gwenzek commented 3 years ago

Hi, I saw your presentation during the Zig show and got interested. I love the idea of being able to have such high-level programming style in Zig.

But I've some hard time understanding the examples. Could you maybe write a FizzBuzz implementation ?

I've tried myself, but I didn't find a way to properly remove the console for the number that divides 3 or 5. Removing any one of them, seems to optimize away all the pipeline. Therefore I'm still printing to the console.

pub fn main() !void {
    ...
    const pFizzBuzz = .{
        .{ F.gen, .{30} }, // stage
        .{ .not3, F.exactdiv, .{3} },
        .{ .not5, F.exactdiv, .{5} },
        // Divisible by 3 and 5
        .{ F.ack, .{"div15"} },
        .{ F.console, ._ },
        // Divisible by 3 but not 5
        .{.not5},
        .{ F.ack, .{"div3"} },
        .{ F.console, ._ },
        // Not Divisible by 3
        .{.not3},
        .{ .not3not5, F.exactdiv, .{5} },
        // Divisible by 5 but not 3
        .{ F.ack, .{"div5"} },
        .{ F.console, ._ },
        // Not divisible by 3 or 5
        .{.not3not5},
        .{ F.console, ._ },
    };

    var sFizzBuzz = Make.Mint(pFizzBuzz).init(allocator);
    const fizzBuzzCtx = struct {
        pub var div15 = "\nFizzBuzz";
        pub var div3 = "\nFizz";
        pub var div5 = "\nBuzz";
    };
    try sFizzBuzz.run(fizzBuzzCtx);
}

My ack filter:

        /// Display a message in the stdout every time we receive an element.
        /// The element is passed downstream
        pub fn ack(self: *S, slc: ?[]const u8) callconv(.Async) !void {
            defer self.endStage();
            if (debugStart) std.log.info("start {}_{s}", .{ self.i, self.name });
            try self.selectOutput(0);
            const stdout = std.io.getStdOut().writer();
            while (true) {
                const e = try self.peekTo(T);
                try stdout.print("{s}", .{slc.?});
                try self.output(e);
                _ = try self.readTo(T);
            }
            return self.ok();
        }

Output:

FizzBuzz0 
Fizz3 1 2 
Fizz6 
Buzz5 4 
Fizz9 7 
Fizz12 
Buzz10 8 11 
FizzBuzz15 13 14 
Fizz18 16 17 
Fizz21 
Buzz20 19 
Fizz24 22 
Fizz27 
Buzz25 23 26 28 29 

Also about the API, I found it a bit awkward that exactDiv expect the label for it's output on the left side. I think .{ F.exactdiv, .{3}, .not3 } would be easier to read.

edt-xx commented 2 years ago

Take a look at the "FizzBuzz" commit. The pipe to process FizzBuzz added to main.zig looks like this:

const S = pipe.Filters(F.S, []const u8);

    try Make.run(@This(), .{
    .{ F.gen, .{35} }, 
    .{ .not3, F.exactdiv, .{3} },
    .{ .by3not5, F.exactdiv, .{5} },
    .{ S.replace, .{ @as([]const u8, "\'FizzBuzz")} },    // Divisible by 3 and 5
    .{ .all, F.faninany },
    .{ F.console, ._ },
    .{ .by3not5 },
    .{ S.replace, .{ @as([]const u8, "\'Fizz")} },        // Divisible by 3 but not 5
    .{ .all, ._ },
    .{ .not3 },
    .{ .not3not5, F.exactdiv, .{5} },                     // not divisible by 3, check 5
    .{ S.replace, .{ @as([]const u8, "\'Buzz")} },
    .{ .all, ._ },
    .{ .not3not5 },                                       // route numbers back to faninany 
    .{ .all, ._ },
});

which outputs

FizzBuzz 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34