diff options
| author | Nic Gaffney <gaffney_nic@protonmail.com> | 2025-10-20 03:02:35 -0500 | 
|---|---|---|
| committer | Nic Gaffney <gaffney_nic@protonmail.com> | 2025-10-20 03:02:35 -0500 | 
| commit | b4588b2064c3afde9497084caef6e83246b32501 (patch) | |
| tree | 0a25bd30b6f812a2acc9ba35f5c72ba20e9f7844 /src | |
| parent | 0729305769365c9d29689a52ec37dbd3818a28a4 (diff) | |
| download | funcz-b4588b2064c3afde9497084caef6e83246b32501.tar.gz | |
Added docstrings with proper type signatures
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.zig | 97 | 
1 files changed, 59 insertions, 38 deletions
| diff --git a/src/lib.zig b/src/lib.zig index c84829f..0a50a80 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -1,18 +1,33 @@  const std = @import("std"); +const Type = std.builtin.Type; -/// Compose two single argument functions +fn typeVerify(T: type, expected: anytype) Type { +    const expectedType = @TypeOf(expected); +    const expectedTypeInfo = @typeInfo(expectedType); +    if (expectedTypeInfo != .@"struct") +        @compileError("Expected struct or tuple, found " ++ @typeName(expectedType)); +    const realTypeInfo = @typeInfo(T); +    for (expected) |e| { +        if(realTypeInfo == e) return realTypeInfo; +    } +    for (expected) |e| +        @compileError("Expected one of " ++ @tagName(e) ++ ", found " ++ @typeName(T)); +    return realTypeInfo; +} + +/// ```zig +/// (fn (fn (b) c, fn (a) b) fn (a) c) +/// ``` +/// Function composition +/// Type signature: (a -> b) -> (b -> c) -> (a -> c) +/// `outerFunc` and `innerFunc` are functions of types `b -> c` and `a -> b` respectively +/// Haskell equivalent: `outerFunc . innerFunc`  pub fn compose(      comptime outerFunc: anytype,      comptime innerFunc: anytype  ) blk:{ -    const outerFuncType = @TypeOf(outerFunc); -    const outerFuncTypeInfo = @typeInfo(outerFuncType); -    if(outerFuncTypeInfo != .@"fn") -        @compileError("Expected function, found " ++ @typeName(outerFuncType)); -    const innerFuncType = @TypeOf(innerFunc); -    const innerFuncTypeInfo = @typeInfo(innerFuncType); -    if(innerFuncTypeInfo != .@"fn") -        @compileError("Expected function, found " ++ @typeName(innerFuncType)); +    _=typeVerify(@TypeOf(outerFunc), .{ .@"fn" }); +    _=typeVerify(@TypeOf(innerFunc), .{ .@"fn" });      const out = @typeInfo(@TypeOf(outerFunc)).@"fn".return_type.?;      const in = @typeInfo(@TypeOf(innerFunc)).@"fn".params[0].type.?;      break :blk fn(in) out; @@ -26,54 +41,60 @@ pub fn compose(      }.func;  } +/// ```zig +/// (fn (Allocator, fn (fn (a) b, []a) error{OutOfMemory}![]b) +/// ``` +/// Map a function onto a list of values, allocating space for the new slice +/// Type signature: `(a -> b) -> [a] -> [b]` +/// `func` is of type `a -> b`, where `items` is of type `[a]`. +/// `map` will return a slice of type `[b]` +/// Haskell equivalent: `map func items`  pub fn mapAlloc(      allocator: std.mem.Allocator,      func: anytype,      items: anytype,  ) error{OutOfMemory}!blk:{ -    const itemsType = @TypeOf(items); -    const itemsTypeInfo = @typeInfo(itemsType); -    const funcType = @TypeOf(func); -    const funcTypeInfo = @typeInfo(funcType); -    if(funcTypeInfo != .@"fn") -        @compileError("Expected function, found " ++ @typeName(funcType)); -    if(itemsTypeInfo != .array and itemsTypeInfo != .pointer) { -        @compileError("Expected array or slice, found " ++ @typeName(itemsType)); -    } -    switch (itemsTypeInfo) { -        .pointer => |p| if(p.size != .many and p.size != .slice) @compileError("Expected pointer of size 'many' or 'slice', found " ++ @tagName(p)), +    const funcInfo = typeVerify(@TypeOf(func), .{ .@"fn" }); +    const itemsInfo = typeVerify(@TypeOf(items), .{ .array, .pointer }); +    switch (itemsInfo) { +        .pointer => |p| if(p.size != .many and p.size != .slice) +            @compileError("Expected pointer of size 'many' or 'slice', found " ++ @tagName(p)),          else =>{},      } -    break :blk []funcTypeInfo.@"fn".return_type.?; +    break :blk []funcInfo.@"fn".return_type.?;  } { -    const funcType = @TypeOf(func); -    const funcTypeInfo = @typeInfo(funcType); -    var result = try allocator.alloc(funcTypeInfo.@"fn".return_type.?, items.len); +    const funcInfo = typeVerify(@TypeOf(func), .{ .@"fn" }); +    var result = try allocator.alloc(funcInfo.@"fn".return_type.?, items.len);      for(items, 0..) |item, i|          result[i] = func(item);      return result;  } +/// ```zig +/// (fn (Allocator, fn (fn (a) b, []a, *[]b) void) +/// ``` +/// Map a function onto a list of values, using a buffer +/// Type signature: `(a -> b) -> [a] -> [b]` +/// `func` is of type `a -> b`, where `items` is of type `[a]` and `buffer` is a pointer to a value of type `[b]`. +/// Haskell equivalent: `map func items`  pub fn map(      func: anytype,      items: anytype,      buffer: anytype,  ) void { -    const funcType = @TypeOf(func); -    const bufferType = @TypeOf(buffer); -    const itemsType = @TypeOf(items); -    const funcTypeInfo = @typeInfo(funcType); -    const bufferTypeInfo = @typeInfo(bufferType); -    const itemsTypeInfo = @typeInfo(itemsType); -    if(funcTypeInfo != .@"fn") -        @compileError("Expected function, found " ++ @typeName(funcType)); -    if(itemsTypeInfo != .array and itemsTypeInfo != .pointer) -        @compileError("Expected array, found " ++ @typeName(itemsType)); -    if(bufferTypeInfo != .array and bufferTypeInfo != .pointer) -        @compileError("Expected array, found " ++ @typeName(bufferType)); -    switch (itemsTypeInfo) { -        .pointer => |p| if(p.size != .many and p.size != .slice) @compileError("Expected pointer of size 'many' or 'slice', found '" ++ @tagName(p.size) ++ "'"), +    _=typeVerify(@TypeOf(func), .{ .@"fn" }); +    const itemsInfo = typeVerify(@TypeOf(items), .{ .pointer, .array }); +    const bufferInfo = typeVerify(@TypeOf(buffer), .{ .pointer }); +    const bufferChildInfo = typeVerify(bufferInfo.pointer.child, .{ .pointer, .array }); +    switch (itemsInfo) { +        .pointer => |p| if(p.size != .many and p.size != .slice) +            @compileError("Expected pointer of size 'many' or 'slice', found '" ++ @tagName(p.size) ++ "'"), +        else =>{}, +    } +    switch (bufferChildInfo) { +        .pointer => |p| if(p.size != .many and p.size != .slice) +            @compileError("Expected pointer of size 'many' or 'slice', found '" ++ @tagName(p.size) ++ "'"),          else =>{},      }      for (items, 0..) |item, i| | 
