@@ -0,0 +1,333 @@
1+---
2+title: Nix
3+subtitle: Язык, пакетный менеджер и экосистема
4+author: Александр Бантьев
5+theme: Madrid
6+colortheme: dolphin
7+mainfont: Roboto
8+monofont: Hack
9+aspectratio: 169
10+titlegraphic: nix.png
11+header-includes:
12+- \usepackage[utf8]{inputenc}
13+- \usepackage[russian]{babel}
14+---
15+
16+# Вступление
17+
18+## Что такое nix?
19+Nix - это чистый функциональный язык с динамическим типизированием и пакетный менеджер на основе этого языка.
20+
21+Философия Nix как пакетного менеджера - атомарность, повторяемость и чистота сборки.
22+
23+Как язык, Nix отличается упором на ленивые вычисления и ориентированностью на данные: большая часть кода на Nix представляет из себя напоминающие JSON множества аттрибутов (attrsets).
24+
25+## Экосистема
26+{ height=90% }
27+
28+# Nix как язык
29+
30+## Nix как язык
31+Рассмотрим основы синтаксиса Nix.
32+
33+### Краткая инструкция для желающих повторить
34+```bash
35+$ curl https://nixos.org/nix/install | sh
36+<...>
37+$ nix repl
38+```
39+
40+## Числа, арифметика и комментарии
41+```
42+nix-repl> :t 4 # Показать тип выражения
43+an integer
44+nix-repl> 1 + 2 - 3 * 2
45+-3
46+nix-repl> 1 / 2
47+0
48+nix-repl> builtins.add 1 2
49+3
50+nix-repl> # Однострочный комментарий
51+nix-repl> /* Многострочный комментарий */
52+```
53+### Замечание
54+Арифметические операторы лучше обносить пробелами! У символов `/` и `-` есть особые значения в Nix
55+```
56+nix-repl> 6/2
57+/home/balsoft/6/2
58+```
59+
60+## Булевы, булева арифметика и if
61+```
62+nix-repl> :t true
63+a boolean
64+nix-repl> true && false
65+false
66+nix-repl> true || false
67+true
68+nix-repl> if true || false then 3 else 4
69+3
70+nix-repl> if false then 5 else 6
71+6
72+```
73+
74+## Строки (strings)
75+```
76+nix-repl> "foo"
77+"foo"
78+nix-repl> :t "foo"
79+a string
80+nix-repl> "Привет"
81+"Привет"
82+nix-repl> ''foo''
83+"foo"
84+nix-repl> ''
85+ foo
86+ bar
87+ ''
88+"foo\nbar\n"
89+```
90+
91+
92+## Переменные и стороковая интерполяция
93+```
94+nix-repl> foo = "hello"
95+nix-repl> "${foo}, world!"
96+"hello, world!"
97+```
98+
99+### Замечание
100+Названия переменных могут содержать знак `-`
101+```
102+nix-repl> foo-bar = 10
103+nix-repl> foo-bar
104+10
105+```
106+Но не могут содержать не-ASCII!
107+```
108+nix-repl> привет
109+error: syntax error, unexpected $undefined, at (string):1:1
110+```
111+
112+## Как избежать интерполяции?
113+Довольно часто встречаются ситуации, когда мы хотим вставить в строку последовательность `${...}` (например, в bash-код).
114+
115+```
116+nix-repl> "\${foo}"
117+"${foo}"
118+
119+nix-repl> ''test ''${foo} test''
120+"test ${foo} test"
121+```
122+
123+## Пути (paths) и URL
124+
125+```
126+nix-repl> /bin/sh
127+/bin/sh
128+nix-repl> :t /bin/sh
129+a path
130+nix-repl> ./hello # Относительно текущего .nix файла или PWD для repl
131+/home/balsoft/hello
132+nix-repl> https://typeable.io
133+"https://typeable.io"
134+nix-repl> :t https://typeable.io
135+a string
136+```
137+### Замечание
138+Пути, как и названия переменных, не могут содержать не-ASCII. Я бы рассматривал это, как баг.
139+```
140+nix-repl> /home/balsoft/Документы
141+error: path '/home/balsoft/' has a trailing slash
142+```
143+
144+## Списки (lists)
145+
146+Списки в Nix иммутабельны и могут содержать значения любых типов вперемешку.
147+
148+```
149+nix-repl> [ 2 "foo" true (2+3) ]
150+[ 2 "foo" true 5 ]
151+
152+```
153+
154+### Замечание
155+Обратите внимание: элементы списка не разделены запятыми!
156+```
157+nix-repl> [ 1 + 2 ]
158+error: syntax error, unexpected '+', at (string):1:5
159+nix-repl> [ (1 + 2) ]
160+[ 3 ]
161+nix-repl> [ import ./hello.nix {} ]
162+[ «primop-app» /home/balsoft/hello.nix { ... } ]
163+```
164+
165+## Множества аттрибутов (attribute sets, attrsets)
166+```
167+nix-repl> s = { foo = "bar"; a-b = "baz"; "123" = "num"; }
168+nix-repl> s
169+{ "123" = "num"; a-b = "baz"; foo = "bar"; }
170+nix-repl> s.a-b
171+"baz"
172+nix-repl> s."123"
173+"num"
174+nix-repl> s.${toString (122 + 1)}
175+"num"
176+nix-repl> s.abc or "not found" # Note that `or` is a keyword
177+"not found"
178+nix-repl> s // { a = 10; }
179+{ "123" = "num"; a = 10; a-b = "baz"; foo = "bar"; }
180+nix-repl> rec { a = 3; b = a + 4; } # Recursive attrset
181+{ a = 3; b = 7; }
182+```
183+
184+
185+## Let и with
186+```
187+nix-repl> let a = 3; b = 4; in a + b
188+7
189+nix-repl> let a = 4; b = a + 5; in b # Let definitions are recursive
190+9
191+nix-repl> let a = 3; a = 8; in a
192+error: attribute `a' at (string):1:12 already defined at (string):1:5
193+nix-repl> longName = { a = 3; b = 4; }
194+nix-repl> longName.a + longName.b
195+7
196+nix-repl> with longName; a + b
197+7
198+```
199+
200+## Функции (functions)
201+```
202+nix-repl> x: x*2
203+«lambda»
204+nix-repl> double = x: x * 2
205+nix-repl> :t double
206+a function
207+nix-repl> double 3
208+6
209+nix-repl> greet = end: name: "Hello, ${name} ${end}"
210+nix-repl> greet "dredozubov" "!"
211+"Hello, dredozubov !"
212+nix-repl> greetExclamaition = greet "!"
213+nix-repl> greetExclamaition "s9gf4ult"
214+"Hello, s9gf4ult !"
215+```
216+
217+## Паттерн-матчинг
218+```
219+nix-repl> greet = { name, end }: "Hello, ${name} ${end}"
220+nix-repl> greet { name = "ak3n"; exc = "!"; }
221+"Hello, ak3n !"
222+nix-repl> greet = { name, end ? "!" }: "Hello, ${name} ${end}"
223+nix-repl> greet { name = "ak3n"; }
224+"Hello, ak3n !"
225+nix-repl> greet { name = "ak3n"; end = "."; }
226+"Hello, ak3n ."
227+nix-repl> greet = { name, end ? "!", ... }: "Hello, ${name} ${end}"
228+nix-repl> greet { name = "ak3n"; end = "."; extra = true; }
229+"Hello, ak3n ."
230+nix-repl> foo = {a, ...}@args: args // { a = a + 3; }
231+nix-repl> foo { a = 10; b = 11; }
232+{ a = 13; b = 11; }
233+```
234+
235+## Подключения файлов (import)
236+### number.nix
237+```
238+3
239+```
240+### function.nix
241+```
242+a: a + 3
243+```
244+### Обратно в наш уютный repl
245+```
246+nix-repl> a = import ./number.nix
247+nix-repl> f = import ./function.nix
248+nix-repl> f a
249+6
250+```
251+
252+## Деривации (derivation)
253+```
254+nix-repl> d = derivation {
255+ name = "myname";
256+ builder = "mybuilder";
257+ system = "mysystem";
258+ }
259+nix-repl> :t d
260+a set
261+nix-repl> d
262+«derivation /nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv»
263+```
264+
265+### Лирическое отступление
266+На этом этапе нужно рассмотреть, что же представляет из себя nix-the-package-manager.
267+
268+# Пакетный менеджер Nix
269+## Хранилище (nix store)
270+> In the beginning was the Store, and the Store was with Nix, and the Store was Nix.
271+
272+*-- Nix manual, 1:1*
273+
274+```bash
275+$ ls /nix/store | wc -l
276+46251
277+$ nix add-to-store nix.conf
278+/nix/store/za34q8y0jcx3qsrnbrd005mh8zcnlrlr-nix.conf
279+
280+```
281+
282+## Деривации
283+```bash
284+$ cat /nix/store/z3hhlxbckx4g3n9sw91nnvlkjvyw754p-myname.drv
285+Derive
286+([("out","/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname","","")]
287+,[]
288+,[]
289+,"mysystem"
290+,"mybuilder"
291+,[]
292+,[("builder","mybuilder")
293+ ,("name","myname")
294+ ,("out","/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname")
295+ ,("system","mysystem") ] )
296+```
297+
298+## Принцип работы
299+```diagram
300+text' s t = text t # fontSize (local s) <> strutY (s * 1.3)
301+
302+
303+sideText' s t = baselineText t # fontSize (local s)
304+
305+box t = text' 0.2 t # fc white # font "hack" <> roundedRect 2 0.4 0.2 # fc blue
306+
307+av = unitY ^* (-0.5)
308+
309+boxes = box "myname.nix" # named "nix"
310+ ===
311+ (strutY 0.5 <> sideText' 0.1 "Вычисление (nix как язык)")
312+ ===
313+ box "myname.drv" # named "drv"
314+ ===
315+ (strutY 0.5 <> sideText' 0.1 "Сборка (nix как пакетный менеджер)")
316+ ===
317+ box " myname " # named "out"
318+
319+arrows = arrowBetween (0 ^& (-0.2)) (0 ^& (-0.7))
320+ <> arrowBetween (0 ^& (-1.1)) (0 ^& (-1.6))
321+
322+example = boxes <> arrows
323+```
324+
325+*На эту диаграмму ушло четыре с половиной часа. Ненавижу `diagrams`, `diagrams-pandoc` и `svg-fonts`*
326+
327+
328+# Заключение
329+## Ссылки
330+https://nixos.org/
331+https://imgur.com/0gPQ4zg
332+
333+