<commit_before>#title.step(data-x="0" data-y="0" data-scale="4")
  // h4 introducing
  h1.nix-name nix
  h2 the purely functional package manager.

.step
  h3 What is nix?
  p.substep Nix is a <i>package manager</i>.
  p.substep Nix is a <i>language</i>.

.step(data-x="0" data-y="-1000")
  p Nix does things quite differently from most package managers, and this gives it some distinct advantages.
  p.substep.small (And a few disadvantages as well.)

.step(data-x="1000" data-y="-5000" data-z="-5000")
  h3 Immutable builds
  p.substep Once packages are built, they don't change.
  p.substep If the definition of a package changes from the last time it was built, it is treated as a <strong>new package</strong> instead.
  p.substep This makes it very easy to reason about the state of packages on the system.

.step(data-x="1000" data-y="-5000" data-z="-10000")
  h3 No shared build location
  p.substep Each package is built in its own folder.
  p.substep Those folders are guaranteed to be distinct from each other.
  p.substep The name of the folder is derivable from the definition of the package.
  p.substep Coupled with the immutable builds rule, this means that the same package only needs to be built once.

.step(data-x="1000" data-y="-5000" data-z="-15000")
  h3 Turing complete, functional definition language
  p.substep Nix packages are defined in a DSL (also called <span class="generic-code">nix</span>), which contains as first-class values, among other things:
  ul
    li.substep Numbers, booleans, strings
    li.substep Lists
    li.substep Dictionaries
    li.substep Functions
  p.substep This means that package definitions can be <i>parameterized</i> in the same way that you might generalize a piece of code by giving parameters to a function.
  p.substep It also means that by and large, you can compute whatever logic you need in nix itself, including making decisions about dependencies, custom build steps, etc.

.step(data-x="6000" data-y="4000" data-scale="2")
  p Also...

.step(data-x="6200" data-y="4300" data-z="-100" data-rotate-x="-40" data-rotate-y="10" data-scale="2")
  p Nix is just really fun to write!
  p.substep.small Plus, you learn about functional programming, which is pretty sweet.

.step(data-x="0" data-y="-3000" data-z="-1500")
  h3 Let's get started!

.step(data-x="1000" data-y="-3000" data-z="-1500")
  p We'll start by looking at a package that's already installed.
  p.substep.generic-code $ which vim
  p.substep.generic-code $ ls -l $(which vim)
  p.substep.generic-code $ ldd $(which vim)

.step(data-x="1000" data-y="-1500")
  h3 Now let's try installing something!
  p.substep How about <span class="generic-code">nix-repl</span>? That could be useful...
  p.substep.generic-code $ nix-env --dry-run -iA nixpkgs.nix-repl
  pre.substep.generic-code(width=100).
    (dry run; not doing anything)
    installing ‘nix-repl-1.10-8a2f5f0’
    these paths will be fetched (3.36 MiB download, 9.99 MiB unpacked):
      /nix/store/0p8d8y9zga8r6mw5c5msgah71bm1q13x-curl-7.44.0
      /nix/store/2zmv1niaafzfnx5hywwhcp7xrx8fzywc-nix-1.10
      /nix/store/6m7msardcc7vpzbrxspl9g8a63adkn7k-libsodium-1.0.6
      /nix/store/6v321hlc954yvr9h0ifgvixs0vpm8xhm-nix-repl-1.10-8a2f5f0
      /nix/store/dav20sh5skrwx8qjbay0zalbzf8y0w7c-perl-WWW-Curl-4.17
      /nix/store/gbgq0dgypc3rrxxjxmpg1vsl7nns5cz6-perl-DBD-SQLite-1.48
      /nix/store/ila1pgc3mv2s2sni0yhpl7zivvk5jh7k-libssh2-1.6.0
      /nix/store/lxhszhak8yrw4j24s00g1fnlmrgqgar6-perl-DBI-1.634
      /nix/store/z35b0yjmrhhl0cfxrkymf4387i3pjkjm-sqlite-3.8.11.1

.step(data-x="2000" data-y="-1500" data-rotate-y="40")
  h3 Alright now let's actually install it!
  p.substep.generic-code $ nix-env -iA nixpkgs.nix-repl

.step(data-x="1000" data-y="-1500" data-z="-2000")
  h3 Let's see what got installed...
  p.substep.generic-code $ which nix-repl
  p.substep.generic-code $ ls -l $(which nix-repl)
  p.substep.generic-code $ ldd $(which nix-repl)

.step(data-x="850" data-y="3000" data-rotate="90")
  h3 So what actually happened?
  p.substep We downloaded a bunch of tarballs into <span class="generic-code">/nix/store</span>.
  p.substep A <i>symlink</i> to <span class="generic-code">/nix/store/.../bin/nix-repl</span> got put into our user environment.
  p.substep Notice however that there was no such symlink created for the package <span class="generic-code">curl</span>, which was one of the dependencies of <span class="generic-code">nix-repl</span> -- it wasn't <i>installed</i>, just <i>built</i>. This distinction is a powerful feature of nix.
  p.substep.generic-code $ which curl

.step(data-x="850" data-y="4000" data-rotate="90")
  h3 So how did <span class="generic-code">nix-repl</span> get defined?
  .substep
    p Let's follow its definition through the code...
    p.generic-code $ echo $NIX_PATH
    p.generic-code.substep $ emacs ~/.nix-defexpr/channels/nixpkgs

.step(data-x="3500" data-y="2100" data-rotate="180")
  h3 So looks like we need to learn some of the nix language now.

.step(data-x="2500" data-y="2100" data-rotate="180")
  p Nix is an <i>expression-based</i> language.
  p.substep This means you write expressions, which are descriptions of objects, and it's the computer's job to build those objects.
  p.substep As opposed to a <i>statement-based</i> language, in which you give a series of <i>commands</i>, and it's the computer's job to execute those commands.
  p.substep In an expression-based language, you don't really care what steps the computer is executing, as long as they produce the expected semantics.

.step(data-x="2500" data-y="2600" data-rotate="180")
  p So what are the objects we can define in nix?

.step(data-x="500" data-y="2600" data-rotate="180" data-rotate-y="90")
  ul
    li Simple primitives:
    ul
      li.substep.generic-code 121
      li.substep.generic-code true
      li.substep.generic-code null
      li.substep.generic-code "hello"
    li.substep Lists:
    ul
      li.substep.generic-code [121 true null "hello"]
    li.substep Sets (analogous to JS objects, python dicts):
    ul
      li.substep.generic-code {a = 121; b = true; c = null; d = "hello";}
    li.substep If expressions:
    ul
      li.substep.generic-code if 121 > 100 then "hello" else "world"
    li.substep Operators on primitives:
    ul
      li.substep.generic-code 123 * 456
      li.substep.generic-code "hello " + "world"

.step(data-x="500" data-y="3600" data-rotate-y="90")
  h3 Variables
  p.substep We can introduce variables in a few ways. The most simple is the <span class="generic-code">let</span> expression.
  ul.substep
    li.generic-code let x = 123; in x + 1
    li.generic-code let x = 123; y = 245; in x * y

.step(data-x="500" data-y="4600" data-rotate="180" data-rotate-y="90")
  h3 Functions
  p.substep All functions in nix are lambda functions.
  ul.substep
    li.generic-code addOne = number: number + 1
    li.generic-code identity = anything: anything
  p.substep To apply a function <span class="generic-code">f</span> to an argument <span class="generic-code">x</span>, we can simply write <span class="generic-code">f x</span>. We don't need parentheses.
  ul.substep
    li.generic-code addOne 2
    li.generic-code [(identity 1) (identity "hello")]

.step(data-x="500" data-y="5600" data-rotate-y="90")
  h3 Achievement unlocked: factorial
  p.substep With <span class="generic-code">let</span> and functions, we can write the infamous factorial function:
  pre.substep.generic-code.
    let fact = n: if n == 0 then 1
                  else n * fact (n - 1); in
    fact 10

.step(data-x="500" data-y="6600" data-rotate="180" data-rotate-y="90")
  h3 Functions of more than one argument: nested functions.
  p.substep All functions in nix take one argument.
  p.substep <i>Huh?</i>
  p.substep Yes!
  p.substep <i>So what if I need a function with more than one argument?</i>
  p.substep Use <i>nested functions</i>. This is called currying.
  ul.substep
    li.generic-code add = num1: num2: num1 + num2
  p.substep Two pass in the two arguments then, just write both of them:
  ul.substep
    li.generic-code three = add 1 2
  p.substep Or, you can <i>partially apply</i> the function to make a new function:
  ul.substep
    li.generic-code addOne = add 1
    li.generic-code addTwo = add 2
    li.generic-code addOne 5 + addTwo 6

.step(data-x="500" data-y="7600" data-rotate="180" data-rotate-y="90")
  h3 Functions on sets
  p.substep If a function expects a set as an argument, it can use a special syntax:
  pre.substep.generic-code adder = {x, y}: x + y
  pre.substep.generic-code adder {x = 1; y = 2;}
  p.substep The result is similar to python <span class="generic-code">kwargs</span>, and a lot of functions "in the wild" use it.

.step(data-x="0" data-y="7600")
  h3 The most important function: <span class="generic-code">derivation</span>
  p.substep All packages are defined using this function, although most indirectly.
  p.substep This is where all of the "magic" happens: it's what actually causes nix to put something on your hard drive, in the nix store.

#overlay.step(data-x="3000" data-y="1500" data-z="-3100" data-rotate-y="10" data-rotate-x="90" data-scale="10")
  p Thanks for watching!<commit_msg>what was presented<commit_after>#title.step(data-x="0" data-y="0" data-scale="4")
  h1.nix-name nix
  h2 the purely functional package manager.

.step
  h3 What is nix?
  p.substep Nix is a <i>package manager</i>.
  p.substep Nix is a <i>language</i>.

.step(data-x="0" data-y="-1000")
  p Nix does things quite differently from most package managers, and this gives it some distinct advantages.
  p.substep.small (And a few disadvantages as well.)

.step(data-x="1000" data-y="-5000" data-z="-5000")
  h3 Immutable builds
  p.substep Once packages are built, they don't change.
  p.substep If the definition of a package changes from the last time it was built, it is treated as a <strong>new package</strong> instead.
  p.substep This makes it very easy to reason about the state of packages on the system.

.step(data-x="1000" data-y="-5000" data-z="-10000")
  h3 No shared build location
  p.substep Each package is built in its own folder.
  p.substep Those folders are guaranteed to be distinct from each other.
  p.substep The name of the folder is derivable from the definition of the package.
  p.substep Coupled with the immutable builds rule, this means that the same package only needs to be built once.

.step(data-x="1000" data-y="-5000" data-z="-15000")
  h3 Turing complete, functional definition language
  p.substep Nix packages are defined in a DSL (also called <span class="generic-code">nix</span>), which contains as first-class values, among other things:
  ul
    li.substep Numbers, booleans, strings
    li.substep Lists
    li.substep Dictionaries
    li.substep Functions
  p.substep This means that package definitions can be <i>parameterized</i> in the same way that you might generalize a piece of code by giving parameters to a function.
  p.substep It also means that by and large, you can compute whatever logic you need in nix itself, including making decisions about dependencies, custom build steps, etc.

.step(data-x="6000" data-y="4000" data-scale="2")
  p Also...

.step(data-x="6200" data-y="4300" data-z="-100" data-rotate-x="-40" data-rotate-y="10" data-scale="2")
  p Nix is just really fun to write!
  p.substep.small Plus, you learn about functional programming, which is pretty sweet.

.step(data-x="0" data-y="-3000" data-z="-1500")
  h3 Let's get started!

.step(data-x="1000" data-y="-3000" data-z="-1500")
  p We'll start by looking at a package that's already installed.
  p.substep.generic-code $ which vim
  p.substep.generic-code $ ls -l $(which vim)
  p.substep.generic-code $ ldd $(which vim)

.step(data-x="1000" data-y="-1500")
  h3 Now let's try installing something!
  p.substep How about <span class="generic-code">nix-repl</span>? That could be useful...
  p.substep.generic-code $ nix-env --dry-run -iA nixpkgs.nix-repl
  pre.substep.generic-code(width=100).
    (dry run; not doing anything)
    installing ‘nix-repl-1.10-8a2f5f0’
    these paths will be fetched (3.36 MiB download, 9.99 MiB unpacked):
      /nix/store/0p8d8y9zga8r6mw5c5msgah71bm1q13x-curl-7.44.0
      /nix/store/2zmv1niaafzfnx5hywwhcp7xrx8fzywc-nix-1.10
      /nix/store/6m7msardcc7vpzbrxspl9g8a63adkn7k-libsodium-1.0.6
      /nix/store/6v321hlc954yvr9h0ifgvixs0vpm8xhm-nix-repl-1.10-8a2f5f0
      /nix/store/dav20sh5skrwx8qjbay0zalbzf8y0w7c-perl-WWW-Curl-4.17
      /nix/store/gbgq0dgypc3rrxxjxmpg1vsl7nns5cz6-perl-DBD-SQLite-1.48
      /nix/store/ila1pgc3mv2s2sni0yhpl7zivvk5jh7k-libssh2-1.6.0
      /nix/store/lxhszhak8yrw4j24s00g1fnlmrgqgar6-perl-DBI-1.634
      /nix/store/z35b0yjmrhhl0cfxrkymf4387i3pjkjm-sqlite-3.8.11.1

.step(data-x="2000" data-y="-1500" data-rotate-y="40")
  h3 Alright now let's actually install it!
  p.substep.generic-code $ nix-env -iA nixpkgs.nix-repl

.step(data-x="1000" data-y="-1500" data-z="-2000")
  h3 Let's see what got installed...
  p.substep.generic-code $ which nix-repl
  p.substep.generic-code $ ls -l $(which nix-repl)
  p.substep.generic-code $ ldd $(which nix-repl)

.step(data-x="850" data-y="3000" data-rotate="90")
  h3 So what actually happened?
  p.substep We downloaded a bunch of tarballs into <span class="generic-code">/nix/store</span>.
  p.substep A <i>symlink</i> to <span class="generic-code">/nix/store/.../bin/nix-repl</span> got put into our user environment.
  p.substep Notice however that there was no such symlink created for the package <span class="generic-code">curl</span>, which was one of the dependencies of <span class="generic-code">nix-repl</span> -- it wasn't <i>installed</i>, just <i>built</i>. This distinction is a powerful feature of nix.
  p.substep.generic-code $ which curl

.step(data-x="850" data-y="4000" data-rotate="90")
  h3 So how did <span class="generic-code">nix-repl</span> get defined?
  .substep
    p Let's follow its definition through the code...
    p.generic-code $ echo $NIX_PATH
    p.generic-code.substep $ emacs ~/.nix-defexpr/channels/nixpkgs

.step(data-x="3500" data-y="2100" data-rotate="180")
  h3 So looks like we need to learn some of the nix language now.

.step(data-x="2500" data-y="2100" data-rotate="180")
  p Nix is an <i>expression-based</i> language.
  p.substep This means you write expressions, which are descriptions of objects, and it's the computer's job to build those objects.
  p.substep As opposed to a <i>statement-based</i> language, in which you give a series of <i>commands</i>, and it's the computer's job to execute those commands.
  p.substep In an expression-based language, you don't really care what steps the computer is executing, as long as they produce the expected semantics.

.step(data-x="2500" data-y="2600" data-rotate="180")
  p So what are the objects we can define in nix?

.step(data-x="500" data-y="2600" data-rotate="180" data-rotate-y="90")
  ul
    li Simple primitives:
    ul
      li.substep.generic-code 121
      li.substep.generic-code true
      li.substep.generic-code null
      li.substep.generic-code "hello"
    li.substep Lists:
    ul
      li.substep.generic-code [121 true null "hello"]
    li.substep Sets (analogous to JS objects, python dicts):
    ul
      li.substep.generic-code {a = 121; b = true; c = null; d = "hello";}
    li.substep If expressions:
    ul
      li.substep.generic-code if 121 > 100 then "hello" else "world"
    li.substep Operators on primitives:
    ul
      li.substep.generic-code 123 * 456
      li.substep.generic-code "hello " + "world"

.step(data-x="500" data-y="3600" data-rotate-y="90")
  h3 Variables
  p.substep We can introduce variables in a few ways. The most simple is the <span class="generic-code">let</span> expression.
  ul.substep
    li.generic-code let x = 123; in x + 1
    li.generic-code let x = 123; y = 245; in x * y

.step(data-x="500" data-y="4600" data-rotate="180" data-rotate-y="90")
  h3 Functions
  p.substep All functions in nix are lambda functions.
  ul.substep
    li.generic-code addOne = number: number + 1
    li.generic-code identity = anything: anything
  p.substep To apply a function <span class="generic-code">f</span> to an argument <span class="generic-code">x</span>, we can simply write <span class="generic-code">f x</span>. We don't need parentheses.
  ul.substep
    li.generic-code addOne 2
    li.generic-code [(identity 1) (identity "hello")]

.step(data-x="500" data-y="5600" data-rotate-y="90")
  h3 Achievement unlocked: factorial
  p.substep With <span class="generic-code">let</span> and functions, we can write the infamous factorial function:
  pre.substep.generic-code.
    let fact = n: if n == 0 then 1
                  else n * fact (n - 1); in
    fact 10

.step(data-x="500" data-y="6600" data-rotate="180" data-rotate-y="90")
  h3 Functions of more than one argument: nested functions.
  p.substep All functions in nix take one argument.
  p.substep <i>Huh?</i>
  p.substep Yes!
  p.substep <i>So what if I need a function with more than one argument?</i>
  p.substep Use <i>nested functions</i>. This is called currying.
  ul.substep
    li.generic-code add = num1: num2: num1 + num2
  p.substep Two pass in the two arguments then, just write both of them:
  ul.substep
    li.generic-code three = add 1 2
  p.substep Or, you can <i>partially apply</i> the function to make a new function:
  ul.substep
    li.generic-code addOne = add 1
    li.generic-code addTwo = add 2
    li.generic-code addOne 5 + addTwo 6

.step(data-x="500" data-y="7600" data-rotate="180" data-rotate-y="90")
  h3 Functions on sets
  p.substep If a function expects a set as an argument, it can use a special syntax:
  pre.substep.generic-code adder = {x, y}: x + y
  pre.substep.generic-code adder {x = 1; y = 2;}
  p.substep The result is similar to python <span class="generic-code">kwargs</span>, and a lot of functions "in the wild" use it.

.step(data-x="0" data-y="7600")
  h3 The most important function: <span class="generic-code">derivation</span>
  p.substep All packages are defined using this function, although most indirectly.
  p.substep This is where all of the "magic" happens: it's what actually causes nix to put something on your hard drive, in the nix store.
  p.substep Coming soon: see how this function works!

#overlay.step(data-x="3000" data-y="1500" data-z="-3100" data-rotate-y="10" data-rotate-x="90" data-scale="10")
  p Thanks for watching!
{'fraction_non_alphanumeric': 0.12437111171219908, 'fraction_numerical': 0.04982418176900189, 'mean_word_length': 3.5905140302955054, 'pattern_counts': {'":': 0, '<': 115, '<?xml version=': 0, '>': 117, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3464197', 'n_tokens_mistral': 7103, 'n_tokens_neox': 6437, 'n_words': 2049}