如何在 Zig 實現閉包與 Monads

一個有意思的探索,由於 Zig 目前原生並不支持閉包,因此需要一些小技巧來實現該功能。

fn bar(comptime x: usize) fn (usize) usize {
    return struct {
        pub fn foo(y: usize) usize {
            var counter: usize = 0;
            for (x..y) |i| {
                if ((i % 2) == 0) {
                    counter += i * i;
                }
            }
            return counter;
        }
    }.foo;
}
const std = @import("std");
pub fn main() void {
    const f = bar(10);
    std.debug.print("{any}\n", .{f(20)});
}

在上面中,有兩點需要注意:

  1. 用一個匿名的 struct 來包一下要返回的函數

  2. 閉包捕獲的變量 x 必須是 comptime 的,因爲函數本身就是 comptime 的,如果去掉,會報下面的錯誤:

main.zig:1:18: error: function with comptime-only return type 'fn (usize) usize' requires all parameters to be comptime
main.zig:1:18: note: use '*const fn (usize) usize' for a function pointer type
main.zig:1:8: note: param 'x' is required to be comptime

當有人在編程中使用術語 monad 時,通常指的是一個允許我們安全地進行鏈式調用的包裝器,一個用 Zig 實現的 Maybe monad 如下所以:

fn Maybe(comptime T: type) type {
    return struct {
        val: ?T,
        pub fn apply(self: Maybe(T), fun: *const fn (T) ?T) Maybe(T) {
            if (self.val != null) {
                return Maybe(T){ .val = fun(self.val.?) };
            }
            return Maybe(T){ .val = null };
        }
        pub fn unwrapOr(self: anytype, default: T) T {
            if (self.val != null) {
                return self.val.?;
            }
            return default;
        }
        pub fn init(val: T) @This() {
            return Maybe(T){ .val = val };
        }
    };
}

參考資料

[1] 

Implementing Closures and Monads in Zig: https://zig.news/andrewgossage/implementing-closures-and-monads-in-zig-23kf

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/175kFqhgPlNEMkKQAKZBcg