functions
single-argument functions, currying, patterns, and builtins.
single-argument functions, currying, patterns, and builtins.
nix functions take one argument.
f = x: x + 1
f 3 # 4
x: x + 1. part before the colon is the argument. part after is the body. no parentheses, no =>, no fun keyword.
two arguments? a function that returns a function:
add = a: b: a + b
add 10 3 # 13
a: b: a + b is a: (b: a + b). calling add 10 does not error. it returns a new function:
addTen = add 10
addTen 3 # 13
addTen 7 # 17
add = a: b: a + badd 10=b: 10 + badd 10 3=13nixpkgs uses partial application everywhere. callPackage works because of it.
function application is a space. f x calls f with x. multiple arguments chain: f a b c is ((f a) b) c.
no parentheses unless the argument is a compound expression:
f = x: x * 2
f 3 + 1 # 7
f (3 + 1) # 8
f 3 + 1 is (f 3) + 1. function application binds tighter than arithmetic.
in practice, most nix functions destructure an attribute set:
{ pname, version, src }:
stdenv.mkDerivation {
inherit pname version src;
}
{ pname, version, src }: is a pattern. nix matches the argument and binds each name.
{ pname, version, src, debug ? false }:
caller omits debug, it defaults to false.
greet = { name, greeting ? "hey" }: "${greeting}, ${name}""hello, nix""hey, nix"... for extra attributespassing an attribute not in the pattern is an error:
f = { a, b }: a + b
f { a = 1; b = 2; c = 3; }
# error: function called with unexpected argument 'c'
... accepts and ignores extras:
f = { a, b, ... }: a + b
f { a = 1; b = 2; c = 3; } # 3
@sometimes you need both the destructured names and the whole set:
{ pname, version, ... } @ args:
stdenv.mkDerivation (args // {
meta.description = "${pname} ${version}";
})
@ args binds the entire argument to args. destructure what you need, pass the rest through.
built-in functions living in the builtins set:
builtins.length [ 1 2 3 ] # 3
builtins.map (x: x * 2) [ 1 2 3 ] # [ 2 4 6 ]
builtins.filter (x: x > 2) [ 1 2 3 4 5 ] # [ 3 4 5 ]
builtins.attrNames { b = 2; a = 1; } # [ "a" "b" ]
| builtin | what it does |
|---|---|
map f list | apply f to each element |
filter f list | keep elements where f returns true |
attrNames set | keys, sorted |
attrValues set | values, in key-sorted order |
hasAttr name set | whether the key exists |
elem x list | whether x is in the list |
foldl' f init list | strict left fold |
import path | evaluate a nix file, return its value |
throw msg | abort evaluation |
import ./foo.nix evaluates the file and returns whatever it produces. function? you get a function. attribute set? you get a set. no module system at this level. files evaluate to values.
{ lib, stdenv, fetchurl, openssl ? null }:
stdenv.mkDerivation { ... }
single-argument function. argument is an attribute set. lib, stdenv, fetchurl destructured. openssl defaults to null. callPackage in nixpkgs calls this function with the right arguments. packages never import their dependencies manually.
lazy evaluation is the last language concept, and the one that makes the whole ecosystem possible.