Nix is a simple functional language developed for the Nix package manager and NixOS.
You can evaluate Nix expressions using
nix-instantiate
or nix repl
.
1with builtins; [
2
3 # Comments
4 #=========================================
5
6 # Inline comments look like this.
7
8 /* Multi-line comments
9 look like this. */
10
11
12 # Booleans
13 #=========================================
14
15 (true && false) # And
16 #=> false
17
18 (true || false) # Or
19 #=> true
20
21 (if 3 < 4 then "a" else "b") # Conditional
22 #=> "a"
23
24
25 # Integers and Floats
26 #=========================================
27
28 # There are two numeric types: integers and floats
29
30 1 0 42 (-3) # Some integers
31
32 123.43 .27e13 # A couple of floats
33
34 # Operations will preserve numeric type
35
36 (4 + 6 + 12 - 2) # Addition
37 #=> 20
38 (4 - 2.5)
39 #=> 1.5
40
41 (7 / 2) # Division
42 #=> 3
43 (7 / 2.0)
44 #=> 3.5
45
46
47 # Strings
48 #=========================================
49
50 "Strings literals are in double quotes."
51
52 "
53 String literals can span
54 multiple lines.
55 "
56
57 ''
58 This is called an "indented string" literal.
59 It intelligently strips leading whitespace.
60 ''
61
62 ''
63 a
64 b
65 ''
66 #=> "a\n b"
67
68 ("ab" + "cd") # String concatenation
69 #=> "abcd"
70
71 # String interpolation (formerly known as "antiquotation") lets you embed values into strings.
72 ("Your home directory is ${getEnv "HOME"}")
73 #=> "Your home directory is /home/alice"
74
75
76 # Paths
77 #=========================================
78
79 # Nix has a primitive data type for paths.
80 /tmp/tutorials/learn.nix
81
82 # A relative path is resolved to an absolute path at parse
83 # time, relative to the file in which it occurs.
84 tutorials/learn.nix
85 #=> /the-base-path/tutorials/learn.nix
86
87 # A path must contain at least one slash, so a relative
88 # path for a file in the same directory needs a ./ prefix,
89 ./learn.nix
90 #=> /the-base-path/learn.nix
91
92 # The / operator must be surrounded by whitespace if
93 # you want it to signify division.
94
95 7/2 # This is a path literal
96 (7 / 2) # This is integer division
97
98
99 # Imports
100 #=========================================
101
102 # A nix file contains a single top-level expression with no free
103 # variables. An import expression evaluates to the value of the
104 # file that it imports.
105 (import /tmp/foo.nix)
106
107 # Imports can also be specified by strings.
108 (import "/tmp/foo.nix")
109
110 # Import paths must be absolute. Path literals
111 # are automatically resolved, so this is fine.
112 (import ./foo.nix)
113
114 # But this does not happen with strings.
115 (import "./foo.nix")
116 #=> error: string ‘foo.nix’ doesn't represent an absolute path
117
118
119 # Let
120 #=========================================
121
122 # `let` blocks allow us to bind values to variables.
123 (let x = "a"; in
124 x + x + x)
125 #=> "aaa"
126
127 # Bindings can refer to each other, and their order does not matter.
128 (let y = x + "b";
129 x = "a"; in
130 y + "c")
131 #=> "abc"
132
133 # Inner bindings shadow outer bindings.
134 (let a = 1; in
135 let a = 2; in
136 a)
137 #=> 2
138
139
140 # Functions
141 #=========================================
142
143 (n: n + 1) # Function that adds 1
144
145 ((n: n + 1) 5) # That same function, applied to 5
146 #=> 6
147
148 # There is no syntax for named functions, but they
149 # can be bound by `let` blocks like any other value.
150 (let succ = (n: n + 1); in succ 5)
151 #=> 6
152
153 # A function has exactly one argument.
154 # Multiple arguments can be achieved with currying.
155 ((x: y: x + "-" + y) "a" "b")
156 #=> "a-b"
157
158 # We can also have named function arguments,
159 # which we'll get to later after we introduce sets.
160
161
162 # Lists
163 #=========================================
164
165 # Lists are denoted by square brackets.
166
167 (length [1 2 3 "x"])
168 #=> 4
169
170 ([1 2 3] ++ [4 5])
171 #=> [1 2 3 4 5]
172
173 (concatLists [[1 2] [3 4] [5]])
174 #=> [1 2 3 4 5]
175
176 (head [1 2 3])
177 #=> 1
178 (tail [1 2 3])
179 #=> [2 3]
180
181 (elemAt ["a" "b" "c" "d"] 2)
182 #=> "c"
183
184 (elem 2 [1 2 3])
185 #=> true
186 (elem 5 [1 2 3])
187 #=> false
188
189 (filter (n: n < 3) [1 2 3 4])
190 #=> [ 1 2 ]
191
192
193 # Sets
194 #=========================================
195
196 # A "set" is an unordered mapping with string keys.
197 { foo = [1 2]; bar = "x"; }
198
199 # The . operator pulls a value out of a set.
200 { a = 1; b = 2; }.a
201 #=> 1
202
203 # The ? operator tests whether a key is present in a set.
204 ({ a = 1; b = 2; } ? a)
205 #=> true
206 ({ a = 1; b = 2; } ? c)
207 #=> false
208
209 # The // operator merges two sets.
210 ({ a = 1; } // { b = 2; })
211 #=> { a = 1; b = 2; }
212
213 # Values on the right override values on the left.
214 ({ a = 1; b = 2; } // { a = 3; c = 4; })
215 #=> { a = 3; b = 2; c = 4; }
216
217 # The rec keyword denotes a "recursive set",
218 # in which attributes can refer to each other.
219 (let a = 1; in { a = 2; b = a; }.b)
220 #=> 1
221 (let a = 1; in rec { a = 2; b = a; }.b)
222 #=> 2
223
224 # Nested sets can be defined in a piecewise fashion.
225 {
226 a.b = 1;
227 a.c.d = 2;
228 a.c.e = 3;
229 }.a.c
230 #=> { d = 2; e = 3; }
231
232 # Sets are immutable, so you can't redefine an attribute:
233 {
234 a = { b = 1; };
235 a.b = 2;
236 }
237 #=> attribute 'a.b' at (string):3:5 already defined at (string):2:11
238
239 # However, an attribute's set members can also be defined piecewise
240 # way even if the attribute itself has been directly assigned.
241 {
242 a = { b = 1; };
243 a.c = 2;
244 }
245 #=> { a = { b = 1; c = 2; }; }
246
247
248 # With
249 #=========================================
250
251 # The body of a `with` block is evaluated with
252 # a set's mappings bound to variables.
253 (with { a = 1; b = 2; };
254 a + b)
255 # => 3
256
257 # Inner bindings shadow outer bindings.
258 (with { a = 1; b = 2; };
259 (with { a = 5; };
260 a + b))
261 #=> 7
262
263 # This first line of tutorial starts with "with builtins;"
264 # because builtins is a set that contains all of the built-in
265 # functions (length, head, tail, filter, etc.). This saves
266 # us from having to write, for example, "builtins.length"
267 # instead of just "length".
268
269
270 # Set patterns
271 #=========================================
272
273 # Sets are useful when we need to pass multiple values
274 # to a function.
275 (args: args.x + "-" + args.y) { x = "a"; y = "b"; }
276 #=> "a-b"
277
278 # This can be written more clearly using set patterns.
279 ({x, y}: x + "-" + y) { x = "a"; y = "b"; }
280 #=> "a-b"
281
282 # By default, the pattern fails on sets containing extra keys.
283 ({x, y}: x + "-" + y) { x = "a"; y = "b"; z = "c"; }
284 #=> error: anonymous function called with unexpected argument ‘z’
285
286 # Adding ", ..." allows ignoring extra keys.
287 ({x, y, ...}: x + "-" + y) { x = "a"; y = "b"; z = "c"; }
288 #=> "a-b"
289
290 # The entire set can be bound to a variable using `@`
291 (args@{x, y}: args.x + "-" + args.y) { x = "a"; y = "b"; }
292 #=> "a-b"
293
294 # Errors
295 #=========================================
296
297 # `throw` causes evaluation to abort with an error message.
298 (2 + (throw "foo"))
299 #=> error: foo
300
301 # `tryEval` catches thrown errors.
302 (tryEval 42)
303 #=> { success = true; value = 42; }
304 (tryEval (2 + (throw "foo")))
305 #=> { success = false; value = false; }
306
307 # `abort` is like throw, but it's fatal; it cannot be caught.
308 (tryEval (abort "foo"))
309 #=> error: evaluation aborted with the following error message: ‘foo’
310
311 # `assert` evaluates to the given value if true;
312 # otherwise it throws a catchable exception.
313 (assert 1 < 2; 42)
314 #=> 42
315 (assert 1 > 2; 42)
316 #=> error: assertion failed at (string):1:1
317 (tryEval (assert 1 > 2; 42))
318 #=> { success = false; value = false; }
319
320
321 # Impurity
322 #=========================================
323
324 # Because repeatability of builds is critical to the Nix package
325 # manager, functional purity is emphasized in the Nix language
326 # used to describe Nix packages. But there are a few impurities.
327
328 # You can refer to environment variables.
329 (getEnv "HOME")
330 #=> "/home/alice"
331
332 # The trace function is used for debugging. It prints the first
333 # argument to stderr and evaluates to the second argument.
334 (trace 1 2)
335 #=> trace: 1
336 #=> 2
337
338 # You can write files into the Nix store. Although impure, this is
339 # fairly safe because the file name is derived from the hash of
340 # its contents. You can read files from anywhere. In this example,
341 # we write a file into the store, and then read it back out.
342 (let filename = toFile "foo.txt" "hello!"; in
343 [filename (readFile filename)])
344 #=> [ "/nix/store/ayh05aay2anx135prqp0cy34h891247x-foo.txt" "hello!" ]
345
346 # We can also download files into the Nix store.
347 (fetchurl "https://example.com/package-1.2.3.tgz")
348 #=> "/nix/store/2drvlh8r57f19s9il42zg89rdr33m2rm-package-1.2.3.tgz"
349
350]