<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-module-abstractions">
 <title>Abstractions</title>

 <para>
  If you find yourself repeating yourself over and over, it’s time to
  abstract. Take, for instance, this Apache HTTP Server configuration:
<programlisting>
{
  <xref linkend="opt-services.httpd.virtualHosts"/> =
    { "blog.example.org" = {
        documentRoot = "/webroot/blog.example.org";
        adminAddr = "alice@example.org";
        forceSSL = true;
        enableACME = true;
        enablePHP = true;
      };
      "wiki.example.org" = {
        documentRoot = "/webroot/wiki.example.org";
        adminAddr = "alice@example.org";
        forceSSL = true;
        enableACME = true;
        enablePHP = true;
      };
    };
}
</programlisting>
  It defines two virtual hosts with nearly identical configuration; the only
  difference is the document root directories. To prevent this
  duplication, we can use a <literal>let</literal>:
<programlisting>
let
  commonConfig =
    { adminAddr = "alice@example.org";
      forceSSL = true;
      enableACME = true;
    };
in
{
  <xref linkend="opt-services.httpd.virtualHosts"/> =
    { "blog.example.org" = (commonConfig // { documentRoot = "/webroot/blog.example.org"; });
      "wiki.example.org" = (commonConfig // { documentRoot = "/webroot/wiki.example.com"; });
    };
}
</programlisting>
  The <literal>let commonConfig = <replaceable>...</replaceable></literal>
  defines a variable named <literal>commonConfig</literal>. The
  <literal>//</literal> operator merges two attribute sets, so the
  configuration of the second virtual host is the set
  <literal>commonConfig</literal> extended with the document root option.
 </para>

 <para>
  You can write a <literal>let</literal> wherever an expression is allowed.
  Thus, you also could have written:
<programlisting>
{
  <xref linkend="opt-services.httpd.virtualHosts"/> =
    let commonConfig = <replaceable>...</replaceable>; in
    { "blog.example.org" = (commonConfig // { <replaceable>...</replaceable> })
      "wiki.example.org" = (commonConfig // { <replaceable>...</replaceable> })
    };
}
</programlisting>
  but not <literal>{ let commonConfig = <replaceable>...</replaceable>; in
  <replaceable>...</replaceable>; }</literal> since attributes (as opposed to
  attribute values) are not expressions.
 </para>

 <para>
  <emphasis>Functions</emphasis> provide another method of abstraction. For
  instance, suppose that we want to generate lots of different virtual hosts,
  all with identical configuration except for the document root. This can be done
  as follows:
<programlisting>
{
  <xref linkend="opt-services.httpd.virtualHosts"/> =
    let
      makeVirtualHost = webroot:
        { documentRoot = webroot;
          adminAddr = "alice@example.org";
          forceSSL = true;
          enableACME = true;
        };
    in
      { "example.org" = (makeVirtualHost "/webroot/example.org");
        "example.com" = (makeVirtualHost "/webroot/example.com");
        "example.gov" = (makeVirtualHost "/webroot/example.gov");
        "example.nl" = (makeVirtualHost "/webroot/example.nl");
      };
}
</programlisting>
  Here, <varname>makeVirtualHost</varname> is a function that takes a single
  argument <literal>webroot</literal> and returns the configuration for a virtual
  host. That function is then called for several names to produce the list of
  virtual host configurations.
 </para>
</section>
