Reading the Nix expressions language

by zimbatm https://zimbatm.com

slide: https://zimbatm.com/talks/reading-nix-expressions/

keywords: #pure, #functional, #lazy

Once upon a time...

nixpkgs https://github.com/NixOS/nixpkgs

pkgs/applications/misc/hello/default.nix

{ stdenv, fetchurl }:

stdenv.mkDerivation rec {
  pname = "hello";
  version = "2.10";

  src = fetchurl {
    url = "mirror://gnu/hello/${pname}-${version}.tar.gz";
    sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
  };

  doCheck = true;

  meta = with stdenv.lib; {
    description = "A program that produces a familiar, friendly greeting";
    longDescription = ''
      GNU Hello is a program that prints "Hello, world!" when you run it.
      It is fully customizable.
    '';
    homepage = https://www.gnu.org/software/hello/manual/;
    changelog = "https://git.savannah.gnu.org/cgit/hello.git/plain/NEWS?h=v${version}";
    license = licenses.gpl3Plus;
    maintainers = [ maintainers.eelco ];
    platforms = platforms.all;
  };
}

configuration.nix

{ config, pkgs, ... }: {
  imports = [
    # Include the results of the hardware scan.
    ./hardware-configuration.nix
  ];

  boot.loader.grub.device = "/dev/sda";
  fileSystems."/".device = "/dev/disk/by-label/nixos";

  # Enable the OpenSSH server.
  services.sshd.enable = true;
}

shell.nix

with import <nixpkgs> {};
mkShell {
  buildInputs = [ mdsh ];
}

JSON value

JSON Nix Name
"foo" "foo" string
10 10 int
5.0 5.0 float
[1,2] [1 2] list
{"foo": 5} { foo = 4; } set / attrset
null null null
true false true false bool

Put together

{
  attrsets = { key = "value"; };
  lists = [ 1 2 3 ];
  strings = "hello";
  integers = 10;
  floats = 1.337;
  bools = [ true false ];
  nulls = null;
}

Strings

"some simple string"
'''
  multiline
  strings
'''
https://urls.com

Paths

export NIX_PATH=/home/zimbatm/.nix-defexpr/channels:nixpkgs=/home/zimbatm/src/nixpkgs
{
  relative_path = ./relative;
  absolute_path = /etc/password;
  hpath = ~/.config/nixpkgs/config.nix;
  spath = <nixpkgs>;
}

Functions

lambda curry

a: b: a + b

keyword arguments

{ a, b }: a + b

talk about scoping

Keyword arguments - more

{ stdenv
, libz ? null
, ... }@args:
args

builtins

  • toString <value>
  • import <path>
  • throw <string>
  • map <fn> <list>
  • builtins.trace <string> <value>
  • builtins.fromJSON <string>
  • builtins.toJSON <value>
  • ...

Keywords

let .. in ...

let
  hello = pkgs.hello;
  pkgs = import <nixpkgs> {};
in
  hello

rec

rec {
  name = "${pname}-${version}";
  pname = "hello";
  version = "1.4.2";
  
  src = {
    url = "https://github.com/gnu/hello/tarballs/${version}.tar.gz";
  };
}

with

pkgs:
{
  buildInputs = with pkgs; [ libxml2 libxslt ];
}

inherit

pkgs:
{
  inherit (pkgs) gcc cmake;
}

==

pkgs:
{
  gcc = pkgs.gcc;
  cmake = pkgs.cmake;
}
pkgs: {
  inherit pkgs;
}

==

pkgs: {
  pkgs = pkgs;
}

if .. then .. else

if true then "yes" else "no"

assert

let
  x = import ./x.nix;
in
  assert builtins.typeOf x == "set";
  x

Operators

attrset operators

{
  fileSystems."/".device = "/dev/disk/by-label/nixos";
}
pkgs:
pkgs.hello or pkgs.world
pkgs:
assert pkgs ? hello;
pkgs.hello

boolean operators

true || false
true && false
true -> false

string interpolation

pkgs:
'''
  ${pkgs.hello}/bin/hello > $out
'''

more

{ a = 4; } // { b = 5; }
[ 1 ] ++ [ 4 ]
4 * 5 / 2

Interlude

Functional

Lazy

Pure

missing topics

  • how to debug
  • __functor and __toString
  • the derivation
  • string context

recap

  • pure and function scripting language
  • hopefully you are able to read nix code

The end

Thanks for listening!