{
"$type": "site.standard.document",
"description": "Zig is a functional programming language",
"path": "/posts/zig-ctfp/",
"publishedAt": "2024-08-07T15:38:20.000Z",
"site": "at://did:plc:6n2ngs7zpcpwxz3jaoxj56tu/site.standard.publication/3mo6y7ludvn2h",
"tags": [
"math",
"category theory",
"programming",
"computer science"
],
"textContent": "Let this blog post be living proof that Zig is in fact also a functional\nprogramming language.\n\nWhat?\nWell, there is a famous book called \"Category Theory For Programmers\" (in\nshort, CTFP) that expresses a lot of the core ideas of functional programming\nthrough category theory. CTFP has a set of challenges at the end of each\nchapter, and I aim to do all of them in Zig.\n\nChallenges\n\n1.4.1\nImplement, as best you can, the identity function in your favorite language\n(or the second favorite, if your favorite language happens to be Haskell).\n\nFor functional programming we will make heavy use of anonymous functions. So a\nrecurring pattern we will see is the following:\n\nSolution:\nSo this challenge becomes very easy:\n\nPS.\n\nSince we don't have function type inference in zig, we will make use of types as\nvalues. So the function call looks like:\n\nSome may be somewhat bothered by this syntax. But I think this is still fair\nsince C++'s version of without type inference (ie. using templates) is:\n\n1.4.2\nImplement the composition function in your favorite language. It takes two\nfunctions as arguments and returns a function that is their composition.\n\nThis is still very similar to the previous challenge but we do it twice nested.\n\nSolution:\n\nYou might notice that this only works for unary functions... Maybe in the future\nI'll find a way to compose stuff in a better way. (maybe structs to pass multiple\nparameters in a single parameter?)\n\n1.4.3\nWrite a program that tries to test that your composition function respects\nidentity.\n\nFor this we need to verify that:\n1. \n2. \n\nSolution:\n\n2.7.1\nDefine a higher-order function (or a function object) in your\nfavorite language. This function takes a pure function as an argument and\nreturns a function that behaves almost exactly like , except that it only\ncalls the original function once for every argument, stores the result\ninternallly, and subsequently returns this stored result every time it's called\nwith the same argument. You can tell the memoize function from the original by\nwatching its preformance. For instance, try to memoize a function that takes a\nlong time to evaluate. You'll have to wait for the result the first time you\ncall it, but on sebsquent calls, with the same argument, you should get the\nresult immediately.\n\nThis one's a doozy...\nBasically we need to create a function that will memoize another function.\nAs elegantly expressed in Closure Conversion: How to compile lambda\na closure is simply a lambda that can capture its environment. The way we\ncapture the environment is simply by adding more data fields to the struct!\nSo we simply add a as a data field to the struct.\n\nSolution\nAnd it works!\n\n2.7.2\nTry to memoize a function from your standard library that you normally use to\nproduce random numbers. Does it work?\n\nApparently, it does!\nBut this is only because it is being executed with the same seed, at\ncompiletime.\n\nSolution:\nSince I haven't figured out how to pass functions with different arity, we must\ncreate a wrapper for the standard library's rng. This function will get rid of\nthat argument since we don't need it to produce the random numbers.\n\nLa Fin\nThis is what I've gotten up until now. Zig's syntax is ugly, and I'm not\nparticularly excited about it's design philosophy but damn is it a solid\nlanguage. This little challenge has made me enjoy Zig a lot more than I thought.",
"title": "Zig CTFP"
}