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); ③