344 lines
11 KiB
XML
344 lines
11 KiB
XML
|
<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>
|
||
|
|
||
|
Here <varname>args</varname> is bound to the entire argument, which
|
||
|
is further matched against the pattern <literal>{ x, y, z,
|
||
|
... }</literal>.</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>rec</literal>-expression.</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>
|