git-subtree-dir: third_party/nix
git-subtree-mainline: cf8cd640c1
git-subtree-split: be66c7a6b24e3c3c6157fd37b86c7203d14acf10
		
	
			
		
			
				
	
	
		
			409 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			409 lines
		
	
	
	
		
			12 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 xml:id="sect-let-expressions"><title>Let-expressions</title>
 | 
						|
 | 
						|
<para>A let-expression allows you to 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>
 | 
						|
 | 
						|
  <warning>
 | 
						|
   <para>
 | 
						|
    The <literal>args@</literal> expression is bound to the argument passed to the function which
 | 
						|
    means that attributes with defaults that aren't explicitly specified in the function call
 | 
						|
    won't cause an evaluation error, but won't exist in <literal>args</literal>.
 | 
						|
   </para>
 | 
						|
   <para>
 | 
						|
    For instance
 | 
						|
<programlisting>
 | 
						|
let
 | 
						|
  function = args@{ a ? 23, ... }: args;
 | 
						|
in
 | 
						|
 function {}
 | 
						|
</programlisting>
 | 
						|
    will evaluate to an empty attribute set.
 | 
						|
   </para>
 | 
						|
  </warning></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>
 |