1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
|
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-constructs">
<title>Language Constructs</title>
<simplesect><title>Recursive sets</title>
<para>Recursive sets are just normal sets, but the attributes can
refer to each other. For example,
<programlisting>
rec {
x = y;
y = 123;
}.x
</programlisting>
evaluates to <literal>123</literal>. Note that without
<literal>rec</literal> the binding <literal>x = y;</literal> would
refer to the variable <varname>y</varname> in the surrounding scope,
if one exists, and would be invalid if no such variable exists. That
is, in a normal (non-recursive) set, attributes are not added to the
lexical scope; in a recursive set, they are.</para>
<para>Recursive sets of course introduce the danger of infinite
recursion. For example,
<programlisting>
rec {
x = y;
y = x;
}.x</programlisting>
does not terminate<footnote><para>Actually, Nix detects infinite
recursion in this case and aborts (<quote>infinite recursion
encountered</quote>).</para></footnote>.</para>
</simplesect>
<simplesect><title>Let-expressions</title>
<para>A let-expression allows you define local variables for an
expression. For instance,
<programlisting>
let
x = "foo";
y = "bar";
in x + y</programlisting>
evaluates to <literal>"foobar"</literal>.
</para>
</simplesect>
<simplesect><title>Inheriting attributes</title>
<para>When defining a set it is often convenient to copy variables
from the surrounding lexical scope (e.g., when you want to propagate
attributes). This can be shortened using the
<literal>inherit</literal> keyword. For instance,
<programlisting>
let x = 123; in
{ inherit x;
y = 456;
}</programlisting>
evaluates to <literal>{ x = 123; y = 456; }</literal>. (Note that
this works because <varname>x</varname> is added to the lexical scope
by the <literal>let</literal> construct.) It is also possible to
inherit attributes from another set. For instance, in this fragment
from <filename>all-packages.nix</filename>,
<programlisting>
graphviz = (import ../tools/graphics/graphviz) {
inherit fetchurl stdenv libpng libjpeg expat x11 yacc;
inherit (xlibs) libXaw;
};
xlibs = {
libX11 = ...;
libXaw = ...;
...
}
libpng = ...;
libjpg = ...;
...</programlisting>
the set used in the function call to the function defined in
<filename>../tools/graphics/graphviz</filename> inherits a number of
variables from the surrounding scope (<varname>fetchurl</varname>
... <varname>yacc</varname>), but also inherits
<varname>libXaw</varname> (the X Athena Widgets) from the
<varname>xlibs</varname> (X11 client-side libraries) set.</para>
</simplesect>
<simplesect xml:id="ss-functions"><title>Functions</title>
<para>Functions have the following form:
<programlisting>
<replaceable>pattern</replaceable>: <replaceable>body</replaceable></programlisting>
The pattern specifies what the argument of the function must look
like, and binds variables in the body to (parts of) the
argument. There are three kinds of patterns:</para>
<itemizedlist>
<listitem><para>If a pattern is a single identifier, then the
function matches any argument. Example:
<programlisting>
let negate = x: !x;
concat = x: y: x + y;
in if negate true then concat "foo" "bar" else ""</programlisting>
Note that <function>concat</function> is a function that takes one
argument and returns a function that takes another argument. This
allows partial parameterisation (i.e., only filling some of the
arguments of a function); e.g.,
<programlisting>
map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
evaluates to <literal>[ "foobar" "foobla"
"fooabc" ]</literal>.</para></listitem>
<listitem><para>A <emphasis>set pattern</emphasis> of the form
<literal>{ name1, name2, …, nameN }</literal> matches a set
containing the listed attributes, and binds the values of those
attributes to variables in the function body. For example, the
function
<programlisting>
{ x, y, z }: z + y + x</programlisting>
can only be called with a set containing exactly the attributes
<varname>x</varname>, <varname>y</varname> and
<varname>z</varname>. No other attributes are allowed. If you want
to allow additional arguments, you can use an ellipsis
(<literal>...</literal>):
<programlisting>
{ x, y, z, ... }: z + y + x</programlisting>
This works on any set that contains at least the three named
attributes.</para>
<para>It is possible to provide <emphasis>default values</emphasis>
for attributes, in which case they are allowed to be missing. A
default value is specified by writing
<literal><replaceable>name</replaceable> ?
<replaceable>e</replaceable></literal>, where
<replaceable>e</replaceable> is an arbitrary expression. For example,
<programlisting>
{ x, y ? "foo", z ? "bar" }: z + y + x</programlisting>
specifies a function that only requires an attribute named
<varname>x</varname>, but optionally accepts <varname>y</varname>
and <varname>z</varname>.</para></listitem>
<listitem><para>An <literal>@</literal>-pattern provides a means of referring
to the whole value being matched:
<programlisting> args@{ x, y, z, ... }: z + y + x + args.a</programlisting>
but can also be written as:
<programlisting> { x, y, z, ... } @ args: z + y + x + args.a</programlisting>
Here <varname>args</varname> is bound to the entire argument, which
is further matched against the pattern <literal>{ x, y, z,
... }</literal>. <literal>@</literal>-pattern makes mainly sense with an
ellipsis(<literal>...</literal>) as you can access attribute names as
<literal>a</literal>, using <literal>args.a</literal>, which was given as an
additional attribute to the function.
</para></listitem>
</itemizedlist>
<para>Note that functions do not have names. If you want to give them
a name, you can bind them to an attribute, e.g.,
<programlisting>
let concat = { x, y }: x + y;
in concat { x = "foo"; y = "bar"; }</programlisting>
</para>
</simplesect>
<simplesect><title>Conditionals</title>
<para>Conditionals look like this:
<programlisting>
if <replaceable>e1</replaceable> then <replaceable>e2</replaceable> else <replaceable>e3</replaceable></programlisting>
where <replaceable>e1</replaceable> is an expression that should
evaluate to a Boolean value (<literal>true</literal> or
<literal>false</literal>).</para>
</simplesect>
<simplesect><title>Assertions</title>
<para>Assertions are generally used to check that certain requirements
on or between features and dependencies hold. They look like this:
<programlisting>
assert <replaceable>e1</replaceable>; <replaceable>e2</replaceable></programlisting>
where <replaceable>e1</replaceable> is an expression that should
evaluate to a Boolean value. If it evaluates to
<literal>true</literal>, <replaceable>e2</replaceable> is returned;
otherwise expression evaluation is aborted and a backtrace is printed.</para>
<example xml:id='ex-subversion-nix'><title>Nix expression for Subversion</title>
<programlisting>
{ localServer ? false
, httpServer ? false
, sslSupport ? false
, pythonBindings ? false
, javaSwigBindings ? false
, javahlBindings ? false
, stdenv, fetchurl
, openssl ? null, httpd ? null, db4 ? null, expat, swig ? null, j2sdk ? null
}:
assert localServer -> db4 != null; <co xml:id='ex-subversion-nix-co-1' />
assert httpServer -> httpd != null && httpd.expat == expat; <co xml:id='ex-subversion-nix-co-2' />
assert sslSupport -> openssl != null && (httpServer -> httpd.openssl == openssl); <co xml:id='ex-subversion-nix-co-3' />
assert pythonBindings -> swig != null && swig.pythonSupport;
assert javaSwigBindings -> swig != null && swig.javaSupport;
assert javahlBindings -> j2sdk != null;
stdenv.mkDerivation {
name = "subversion-1.1.1";
...
openssl = if sslSupport then openssl else null; <co xml:id='ex-subversion-nix-co-4' />
...
}</programlisting>
</example>
<para><xref linkend='ex-subversion-nix' /> show how assertions are
used in the Nix expression for Subversion.</para>
<calloutlist>
<callout arearefs='ex-subversion-nix-co-1'>
<para>This assertion states that if Subversion is to have support
for local repositories, then Berkeley DB is needed. So if the
Subversion function is called with the
<varname>localServer</varname> argument set to
<literal>true</literal> but the <varname>db4</varname> argument
set to <literal>null</literal>, then the evaluation fails.</para>
</callout>
<callout arearefs='ex-subversion-nix-co-2'>
<para>This is a more subtle condition: if Subversion is built with
Apache (<literal>httpServer</literal>) support, then the Expat
library (an XML library) used by Subversion should be same as the
one used by Apache. This is because in this configuration
Subversion code ends up being linked with Apache code, and if the
Expat libraries do not match, a build- or runtime link error or
incompatibility might occur.</para>
</callout>
<callout arearefs='ex-subversion-nix-co-3'>
<para>This assertion says that in order for Subversion to have SSL
support (so that it can access <literal>https</literal> URLs), an
OpenSSL library must be passed. Additionally, it says that
<emphasis>if</emphasis> Apache support is enabled, then Apache's
OpenSSL should match Subversion's. (Note that if Apache support
is not enabled, we don't care about Apache's OpenSSL.)</para>
</callout>
<callout arearefs='ex-subversion-nix-co-4'>
<para>The conditional here is not really related to assertions,
but is worth pointing out: it ensures that if SSL support is
disabled, then the Subversion derivation is not dependent on
OpenSSL, even if a non-<literal>null</literal> value was passed.
This prevents an unnecessary rebuild of Subversion if OpenSSL
changes.</para>
</callout>
</calloutlist>
</simplesect>
<simplesect><title>With-expressions</title>
<para>A <emphasis>with-expression</emphasis>,
<programlisting>
with <replaceable>e1</replaceable>; <replaceable>e2</replaceable></programlisting>
introduces the set <replaceable>e1</replaceable> into the lexical
scope of the expression <replaceable>e2</replaceable>. For instance,
<programlisting>
let as = { x = "foo"; y = "bar"; };
in with as; x + y</programlisting>
evaluates to <literal>"foobar"</literal> since the
<literal>with</literal> adds the <varname>x</varname> and
<varname>y</varname> attributes of <varname>as</varname> to the
lexical scope in the expression <literal>x + y</literal>. The most
common use of <literal>with</literal> is in conjunction with the
<function>import</function> function. E.g.,
<programlisting>
with (import ./definitions.nix); ...</programlisting>
makes all attributes defined in the file
<filename>definitions.nix</filename> available as if they were defined
locally in a <literal>let</literal>-expression.</para>
<para>The bindings introduced by <literal>with</literal> do not shadow bindings
introduced by other means, e.g.
<programlisting>
let a = 3; in with { a = 1; }; let a = 4; in with { a = 2; }; ...</programlisting>
establishes the same scope as
<programlisting>
let a = 1; in let a = 2; in let a = 3; in let a = 4; in ...</programlisting>
</para>
</simplesect>
<simplesect><title>Comments</title>
<para>Comments can be single-line, started with a <literal>#</literal>
character, or inline/multi-line, enclosed within <literal>/*
... */</literal>.</para>
</simplesect>
</section>
|