Nix

Личный сайт Go-разработчика из Казани

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]

Further Reading