I write about my descent into the Nix programming language and try to push it to its computational limits.

Nix, the purely functional package manager is pretty good at what it does. It evaluates things lazily for optimal performance and purely such that installations on one machine can be installed exactly the same on other machines. With Nix, comes *Nix expressions* which which is the technical name for the functional language that powers Nix *(For the rest of this blog post, I will refer to Nix expressions (the language) solely as ‘Nix’)*. Now, this language is designed for package management only. It includes a few basic data types: Integers, Floating point numbers, Booleans, Strings, Lists and Sets *(And of course, functions)*. It doesn’t allow you to create new data types or type classes *(as can say, Haskell)*. It doesn’t have fancy pattern matching and has a very minimal “standard library”. So, the question lies: Can Nix do anything beyond package management?

## Trying to do maths in Nix

Surprisingly, Nix has support for the basic arithmetic operations: addition, subtraction, multiplication and division. In addition to this, there are comparisons (greater than, less than etc.) and equality operations. So, there we go - basic maths in Nix! With this, surely we can begin to test the limits of using Nix to perform mathematical calculations.

When starting new programming languages, my normal “hello world” program is the first problem hosted on Project Euler - a website dedicated to maths and computery problems. The first problem is as follows:

Multiples of 3 and 5If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

Now, this seems like a problem with a pretty simple solution - In pseudo code in an imperative language (such as Java), the solution would look something like this:

1
2
3
4
5
6
7

sum = 0;
for i = 0 to 999:
if (i mod 3 == 0) OR (i mod 5 == 0):
sum = sum + i
end if
end for
return sum

Okay, not a problem. Since this is a functional programming language, we don’t have the luxury of a for loop. Instead, Nix provides various “built in” functions via the `builtins`

“library”, which allows us to use a function called `foldl'`

which basically performs a reduction on a list *(You can read more about folds here)*. In pseudo code, we have some sort of function that adds the counter value to some accumulator (similar to sum) and then “iterate” over the list of numbers from 0 to 999:

1
2
3
4
5
6
7
8
9

-- Definition of foldl' (for this example):
-- foldl' (a -> a -> a) -> a -> [a] -> a
-- foldl' (accumulator -> i -> result) -> baseValue -> list -> returnedValue
list = [0 .. 999]
foldl' (accumulator -> i -> (
if (i mod 3 == 0) OR (i mod 5 == 0):
return accumulator + i
) 0 list

Still following? If so, great - we’ve basically got the algorithm we need for this problem! All we do is basically write that pseudo code and we’re done. Except of course, Nix doesn’t have a `mod`

function. Not by default. There is no `%`

operator and there is no `builtins.mod`

function. Instead, for the luxury of performing the modulo of two numbers, I have to look towards Nixpkgs’s trivial.nix file, which has the `mod`

function.

After adding the mod function, we’re finally ready to solve the problem and to much surprise, Nix handled it with ease. Using this success as inspiration, I work on creating a mini “maths library” for Nix, which included various functions, such as square root *(Using the NewtonRaphson method for approximating functions)* and the `ln`

function *(Using a summing series approximation)* which showed that Nix was indeed able to compute such things.

## Generating SVGs with Nix

As a proof of concept, I also wanted to find out if Nix could produce some sort of “useful” file, such as an SVG. The reason for this file choice is that SVGs can require all sorts of maths and since I’ve written some basic maths library, I could probably use that to generate various graphics using that. For those that don’t know, SVGs are basically image files written in XML which define how the image looks.

In Nix’s `builtins`

library, there is a function called `toXML`

which (surprise surprise) converts a Nix expression to an XML string. Unfortunately, the attributes of the resulting XML file didn’t meet my requirements, meaning I had to write this thing from scratch. Overall, it wasn’t too bad - write an XML header, write the SVG tag and then write various functions that can draw whatever I want. For example, to draw a rectangle, I used the function as follows:

1
2
3
4
5
6
7
8

rect = {x ? 0, y ? 0, width, height, rounded ? 0}:
let
xVal = if x != 0 then "x=\"${toString x}\" " else "";
yVal = if y != 0 then "y=\"${toString y}\" " else "";
wVal = "width=\"${toString width}\" ";
hVal = "height=\"${toString height}\" ";
rxVal = if rounded != 0 then "rx=\"${toString rounded}\" " else "";
in "<rect ${xVal}${yVal}${wVal}${hVal}${rxVal}/>";

Accept x and y coordinates (default to 0 if unspecified), a width and height and how rounded the corners are (not rounded if unspecified), then we apply the functions as specified and map them to the required attributes for the SVG format and then produce the resulting tag for the file. It’s that easy!

## Creating Nix binaries

So, what if I wanted an executable Nix expression? For example, a file where I could just use `./myNixFile.nix`

and it would produce the output in my terminal window? Well, it so happens that by prefixing any Nix expression with the following, you are able to execute Nix expressions!

1
2
3

#!/run/current-system/sw/bin/nix-instantiate --eval
# Your Nix expression here!
2 + 2

Unfortunately, passing arguments to such a file isn’t so straight forward, you have to use the `--arg`

option to pass them to Nix expressions:

1
2

```
#!/run/current-system/sw/bin/nix-instantiate --eval
x: x + 2
```

For example, to run a file with an argument for x, you would have to use `./myNixFile.nix --arg x 2`

## Conclusion

Overall, I think Nix is pretty powerful, despite being a mere package manager programming language which was *in no way* designed for such capabilities. Although all of this programming may have seemed totally pointless *(which indeed, it is)*, it was a very quick way for me to grasp the entire syntax of the Nix language such that I can easily come up with solutions to problems in Nix.

In the near-future, I plan to explore the rest of Nix’s features, such as the Nixpkgs `lib`

library of Nix functions and hopefully deploy a NixOS machine in the cloud using NixOps!