Language

Updated: September 28, 2024

Nix functional programming language. Key take aways.

Evaluation –> Nix expressions yield one data structure
Lazy Evaluation –> Will only evaluate results that are requested
Purely Functional –> No sequence of operations, any order is fine
Type Inference –> Nix figures out types, do not have to list types
Type Checking –> Nix checks types
Declarative –> List requirements for the build, and nix builds them
Immutable –> Cannot change state, only build a new one.
Derivation –> A build task
Impermanance –> Deletes a significant of unneeded data from the system during boot

Nix is not a general purpose language. It is a domain specific language.
DSLs are geared for a specific purpose. For nix, that is building programs and systems.


Nix Language

Nix does not care about newlines or indentation.
Anything placed inside a .nix is called an expression (unevaluated)
. key syntax returns values from the expression (evaluated)

[ ]                 # an empty list, separate with spaces, not commas, "quote strings"
{ }                 # an empty set, separate with commas
{ }:                # currying, function with multiple args that transforms into a sequence of functions
myfunc = a: a + 1   # single function
;                   # statement separator or function call
${ var }            # variable using ${interpolation} ensures nix uses the value
?                   # whatever follows is the default optio
+                   # string concatenation
++                  # list concatenation
@                   # provides an attribute to refer to a set of values
->                  # logical implication, False if e1 is true and e2 is false
//                  # merge attributes with preference on right will override or extend

# set of attrributes with defaults in it.
{ pkgs ? import <nixpkgs> {}, lib ? pkgs.lib, ... }:    # the ellipsis ... means the rest of the attributes are ignored

let ... in        # define local variables for use in an expression
with e1; e2       # adds lexical scope of e1 set into e2
rec               # add to lexical scope, like when a var needs the value of another var
import            # import another file, func, expression !! folders need a default.nix
self              # attribute that refers to itself, ie things in the file that are not sourced from an input
inherit           # inherit system is same as system = system
if then           # if conditions require else.  must be if then else.

Functions

# lets see how it pieces together
let
  myfunc = { a, b }: a + b;
in
myfunc { a = 1; b = 2; }    # curried to evaluated functions to produce final output 3 (result)

# what is looks like in a nix expression
{ config, pkgs, ... }:      # curried function

Assert

# check for requirements, if true, perform, otherwise fail and print backtrace
{ localServer ? false
, httpServer ? false
, openssl ? null }:

# each 
assert localServer -> db4 != null; ①
assert httpServer -> httpd != null && httpd.expat == expat; ②
assert sslSupport -> openssl != null && (httpServer -> httpd.openssl == openssl); ③