about summary refs log tree commit diff
path: root/doc/manual/expressions/language-constructs.xml
diff options
context:
space:
mode:
Diffstat (limited to 'doc/manual/expressions/language-constructs.xml')
-rw-r--r--doc/manual/expressions/language-constructs.xml350
1 files changed, 350 insertions, 0 deletions
diff --git a/doc/manual/expressions/language-constructs.xml b/doc/manual/expressions/language-constructs.xml
new file mode 100644
index 000000000000..fe69dba837a1
--- /dev/null
+++ b/doc/manual/expressions/language-constructs.xml
@@ -0,0 +1,350 @@
+<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 &amp;&amp; httpd.expat == expat; <co xml:id='ex-subversion-nix-co-2' />
+assert sslSupport -> openssl != null &amp;&amp; (httpServer -> httpd.openssl == openssl); <co xml:id='ex-subversion-nix-co-3' />
+assert pythonBindings -> swig != null &amp;&amp; swig.pythonSupport;
+assert javaSwigBindings -> swig != null &amp;&amp; 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>