about summary refs log blame commit diff
path: root/doc/manual/expressions/language-constructs.xml
blob: f961ed921bca5678106675fe9e30413e74e82bd0 (plain) (tree)










































                                                                     
                                                                        


















                                                               
                                                                                         









                                                                    








                                                                         



























                                                                     



















                                                               











































































                                                                                    




                                                                             


                                                                     
                                                                           
                                                                        


                                                                              














































































































































                                                                                                                                













                                                                                  












                                                                      
          
<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 xml:id="sect-let-expressions"><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 or in a let-expression 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>

is equivalent to

<programlisting>
let x = 123; in
{ x = x;
  y = 456;
}</programlisting>

and both evaluate 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>

<para>
Summarizing the fragment

<programlisting>
...
inherit x y z;
inherit (src-set) a b c;
...</programlisting>

is equivalent to

<programlisting>
...
x = x; y = y; z = z;
a = src-set.a; b = src-set.b; c = src-set.c;
...</programlisting>

when used while defining local variables in a let-expression or
while defining a 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>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>