<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<!-- 2022-03-14 Mon 13:59 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Empty Product for certain Views</title>
<meta name="generator" content="Org Mode" />
<style>
  #content { max-width: 60em; margin: auto; }
  .title  { text-align: center;
             margin-bottom: .2em; }
  .subtitle { text-align: center;
              font-size: medium;
              font-weight: bold;
              margin-top:0; }
  .todo   { font-family: monospace; color: red; }
  .done   { font-family: monospace; color: green; }
  .priority { font-family: monospace; color: orange; }
  .tag    { background-color: #eee; font-family: monospace;
            padding: 2px; font-size: 80%; font-weight: normal; }
  .timestamp { color: #bebebe; }
  .timestamp-kwd { color: #5f9ea0; }
  .org-right  { margin-left: auto; margin-right: 0px;  text-align: right; }
  .org-left   { margin-left: 0px;  margin-right: auto; text-align: left; }
  .org-center { margin-left: auto; margin-right: auto; text-align: center; }
  .underline { text-decoration: underline; }
  #postamble p, #preamble p { font-size: 90%; margin: .2em; }
  p.verse { margin-left: 3%; }
  pre {
    border: 1px solid #e6e6e6;
    border-radius: 3px;
    background-color: #f2f2f2;
    padding: 8pt;
    font-family: monospace;
    overflow: auto;
    margin: 1.2em;
  }
  pre.src {
    position: relative;
    overflow: auto;
  }
  pre.src:before {
    display: none;
    position: absolute;
    top: -8px;
    right: 12px;
    padding: 3px;
    color: #555;
    background-color: #f2f2f299;
  }
  pre.src:hover:before { display: inline; margin-top: 14px;}
  /* Languages per Org manual */
  pre.src-asymptote:before { content: 'Asymptote'; }
  pre.src-awk:before { content: 'Awk'; }
  pre.src-authinfo::before { content: 'Authinfo'; }
  pre.src-C:before { content: 'C'; }
  /* pre.src-C++ doesn't work in CSS */
  pre.src-clojure:before { content: 'Clojure'; }
  pre.src-css:before { content: 'CSS'; }
  pre.src-D:before { content: 'D'; }
  pre.src-ditaa:before { content: 'ditaa'; }
  pre.src-dot:before { content: 'Graphviz'; }
  pre.src-calc:before { content: 'Emacs Calc'; }
  pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
  pre.src-fortran:before { content: 'Fortran'; }
  pre.src-gnuplot:before { content: 'gnuplot'; }
  pre.src-haskell:before { content: 'Haskell'; }
  pre.src-hledger:before { content: 'hledger'; }
  pre.src-java:before { content: 'Java'; }
  pre.src-js:before { content: 'Javascript'; }
  pre.src-latex:before { content: 'LaTeX'; }
  pre.src-ledger:before { content: 'Ledger'; }
  pre.src-lisp:before { content: 'Lisp'; }
  pre.src-lilypond:before { content: 'Lilypond'; }
  pre.src-lua:before { content: 'Lua'; }
  pre.src-matlab:before { content: 'MATLAB'; }
  pre.src-mscgen:before { content: 'Mscgen'; }
  pre.src-ocaml:before { content: 'Objective Caml'; }
  pre.src-octave:before { content: 'Octave'; }
  pre.src-org:before { content: 'Org mode'; }
  pre.src-oz:before { content: 'OZ'; }
  pre.src-plantuml:before { content: 'Plantuml'; }
  pre.src-processing:before { content: 'Processing.js'; }
  pre.src-python:before { content: 'Python'; }
  pre.src-R:before { content: 'R'; }
  pre.src-ruby:before { content: 'Ruby'; }
  pre.src-sass:before { content: 'Sass'; }
  pre.src-scheme:before { content: 'Scheme'; }
  pre.src-screen:before { content: 'Gnu Screen'; }
  pre.src-sed:before { content: 'Sed'; }
  pre.src-sh:before { content: 'shell'; }
  pre.src-sql:before { content: 'SQL'; }
  pre.src-sqlite:before { content: 'SQLite'; }
  /* additional languages in org.el's org-babel-load-languages alist */
  pre.src-forth:before { content: 'Forth'; }
  pre.src-io:before { content: 'IO'; }
  pre.src-J:before { content: 'J'; }
  pre.src-makefile:before { content: 'Makefile'; }
  pre.src-maxima:before { content: 'Maxima'; }
  pre.src-perl:before { content: 'Perl'; }
  pre.src-picolisp:before { content: 'Pico Lisp'; }
  pre.src-scala:before { content: 'Scala'; }
  pre.src-shell:before { content: 'Shell Script'; }
  pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
  /* additional language identifiers per "defun org-babel-execute"
       in ob-*.el */
  pre.src-cpp:before  { content: 'C++'; }
  pre.src-abc:before  { content: 'ABC'; }
  pre.src-coq:before  { content: 'Coq'; }
  pre.src-groovy:before  { content: 'Groovy'; }
  /* additional language identifiers from org-babel-shell-names in
     ob-shell.el: ob-shell is the only babel language using a lambda to put
     the execution function name together. */
  pre.src-bash:before  { content: 'bash'; }
  pre.src-csh:before  { content: 'csh'; }
  pre.src-ash:before  { content: 'ash'; }
  pre.src-dash:before  { content: 'dash'; }
  pre.src-ksh:before  { content: 'ksh'; }
  pre.src-mksh:before  { content: 'mksh'; }
  pre.src-posh:before  { content: 'posh'; }
  /* Additional Emacs modes also supported by the LaTeX listings package */
  pre.src-ada:before { content: 'Ada'; }
  pre.src-asm:before { content: 'Assembler'; }
  pre.src-caml:before { content: 'Caml'; }
  pre.src-delphi:before { content: 'Delphi'; }
  pre.src-html:before { content: 'HTML'; }
  pre.src-idl:before { content: 'IDL'; }
  pre.src-mercury:before { content: 'Mercury'; }
  pre.src-metapost:before { content: 'MetaPost'; }
  pre.src-modula-2:before { content: 'Modula-2'; }
  pre.src-pascal:before { content: 'Pascal'; }
  pre.src-ps:before { content: 'PostScript'; }
  pre.src-prolog:before { content: 'Prolog'; }
  pre.src-simula:before { content: 'Simula'; }
  pre.src-tcl:before { content: 'tcl'; }
  pre.src-tex:before { content: 'TeX'; }
  pre.src-plain-tex:before { content: 'Plain TeX'; }
  pre.src-verilog:before { content: 'Verilog'; }
  pre.src-vhdl:before { content: 'VHDL'; }
  pre.src-xml:before { content: 'XML'; }
  pre.src-nxml:before { content: 'XML'; }
  /* add a generic configuration mode; LaTeX export needs an additional
     (add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
  pre.src-conf:before { content: 'Configuration File'; }

  table { border-collapse:collapse; }
  caption.t-above { caption-side: top; }
  caption.t-bottom { caption-side: bottom; }
  td, th { vertical-align:top;  }
  th.org-right  { text-align: center;  }
  th.org-left   { text-align: center;   }
  th.org-center { text-align: center; }
  td.org-right  { text-align: right;  }
  td.org-left   { text-align: left;   }
  td.org-center { text-align: center; }
  dt { font-weight: bold; }
  .footpara { display: inline; }
  .footdef  { margin-bottom: 1em; }
  .figure { padding: 1em; }
  .figure p { text-align: center; }
  .equation-container {
    display: table;
    text-align: center;
    width: 100%;
  }
  .equation {
    vertical-align: middle;
  }
  .equation-label {
    display: table-cell;
    text-align: right;
    vertical-align: middle;
  }
  .inlinetask {
    padding: 10px;
    border: 2px solid gray;
    margin: 10px;
    background: #ffffcc;
  }
  #org-div-home-and-up
   { text-align: right; font-size: 70%; white-space: nowrap; }
  textarea { overflow-x: auto; }
  .linenr { font-size: smaller }
  .code-highlighted { background-color: #ffff00; }
  .org-info-js_info-navigation { border-style: none; }
  #org-info-js_console-label
    { font-size: 10px; font-weight: bold; white-space: nowrap; }
  .org-info-js_search-highlight
    { background-color: #ffff00; color: #000000; font-weight: bold; }
  .org-svg { width: 90%; }
</style>
<script>
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&amp;dn=gpl-3.0.txt GPL-v3-or-Later
     function CodeHighlightOn(elem, id)
     {
       var target = document.getElementById(id);
       if(null != target) {
         elem.classList.add("code-highlighted");
         target.classList.add("code-highlighted");
       }
     }
     function CodeHighlightOff(elem, id)
     {
       var target = document.getElementById(id);
       if(null != target) {
         elem.classList.remove("code-highlighted");
         target.classList.remove("code-highlighted");
       }
     }
// @license-end
</script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        displayAlign: "center",
        displayIndent: "0em",

        "HTML-CSS": { scale: 100,
                        linebreaks: { automatic: "false" },
                        webFont: "TeX"
                       },
        SVG: {scale: 100,
              linebreaks: { automatic: "false" },
              font: "TeX"},
        NativeMML: {scale: 100},
        TeX: { equationNumbers: {autoNumber: "AMS"},
               MultLineWidth: "85%",
               TagSide: "right",
               TagIndent: ".8em"
             }
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML"></script>
</head>
<body>
<div id="content" class="content">
<h1 class="title">Empty Product for certain Views
<br />
<span class="subtitle"> </span>
</h1>
<ul class="org-ul">
<li>Document number: P2540R1</li>
<li>Date:  2022-02-06</li>
<li>Author: Steve Downey &lt;sdowney2@bloomberg.net&gt;, &lt;sdowney@gmail.com&gt;</li>
<li>Audience: SG9, LEWG</li>
</ul>

<div class="ABSTRACT" id="orgec409f0">
<p>
Abstract: This paper argues that the Cartesian product of no ranges should be a single empty tuple, which is the identity element for Cartesian products. Other product-like views, however, should not automatically have their identity be the result, and in particular for <code>zip</code>, as it would introduce unsound inconsistencies.
</p>

</div>



<div id="outline-container-org72249c9" class="outline-2">
<h2 id="org72249c9"><span class="section-number-2">1.</span> Motivation</h2>
<div class="outline-text-2" id="text-1">
<p>
A natural extension of a product of two things is to a product of \(n\) things, that is from \(P = A \times B\) to \(P = \prod_{i=1}^n a_i = a_1 \cdots  a_n\), where the \(\prod\) symbol stands for a repeated product, the same way that \(\sum\) stands for a repeated sum.
For \(n=1\), the expansion immediately suggests that \(P=a_1\), but the \(n=0\) case requires more care.
From the general rule that \(P_n a_{n+1}=P_{n+1}\), we have that \(P_0 a_1=a_1\), so \(P_0\) is the identity for the product.
This convention simplifies induction arguments and sometimes improves consistency with other well defined operations.
For example, having \(0^{0} = 1\), just as \(n^{0} = 1\) for all non-zero numbers, greatly simplifies Taylor series notation.
</p>

<p>
Also note that we are assuming up to isomorphism for types, and in particular that \((a, b, c)\) is isomorphic to \(((a, b), c)\), and \((a, (b, c))\), and further that the unit type \(()\) does not contribute, so that \(((), a) \equiv (a) \equiv (a, ())\). That is there exists a simple and mechanical bijective mapping, one-to-one and onto, between the types.
</p>

<p>
Making the empty product the identity element also puts <code>fold0</code> on a sounder footing. We don't have to supply an identity element because the base case gives it to us automatically.
</p>

<p>
The Cartesian product can also be viewed as the union of all relations between sets.
Any subset of the Cartesian product is a relation among the sets.
For any number of sets, there are always the trivial relations of \(\top\) (every combination is in the relation) and \(\bot\) (the relation is empty).
With zero sets, those are the only two relations, since there is no input variation on which the value might depend.
Accordingly, the Cartesian product of zero sets must have exactly one element (which is the empty tuple \(()\)) so as to have exactly the empty set and the whole set as relations.
</p>

<p>
The most general definition of product comes from Category Theory, of course, where it is well studied. And an important result is that for a Category, such as sets, there is one universal operation that is the product. This should make us suspicious of extending the empty product &equiv; identity rule to other operations.
</p>

<p>
In particular, <code>zip</code> has the property that it is the inner join of the indexed sets, and is the main diagonal of the Cartesian product. However, the identity element for <code>zip</code> is <code>repeat(tuple&lt;&gt;)</code>, the infinite range of repeated empty tuples. If we allowed <code>zip</code> of an empty range of ranges to be its identity element, we would be introducing an inconsistency into the system, where two different formulations of notionally the same thing produces different answers. That would be bad.
</p>
</div>
</div>


<div id="outline-container-org0881987" class="outline-2">
<h2 id="org0881987"><span class="section-number-2">2.</span> Proposal</h2>
<div class="outline-text-2" id="text-2">
<p>
Specify that the Cartesian product of an empty range of ranges is a range of one element, which is the empty tuple, <code>std::tuple&lt;&gt;</code>. The type <code>std::tuple&lt;&gt;</code> is a monostate type, consisting of one element.
This design should <b>not</b> be extended to zip. If it were to be defined, the zip of an empty range of ranges should be the diagonal of the Cartesian product, but this is not actually useful, since that is annihilating for <code>zip</code>. It should be left undefined, as most operations on empty ranges are.
</p>
</div>
</div>


<div id="outline-container-orgd8d8c4a" class="outline-2">
<h2 id="orgd8d8c4a"><span class="section-number-2">3.</span> Wording</h2>
<div class="outline-text-2" id="text-3">
<p>
Wording is relative to p2374r3
</p>
</div>

<div id="outline-container-org059cfaa" class="outline-3">
<h3 id="org059cfaa"><span class="section-number-3">3.1.</span> Overview [range.cartesian.overview]</h3>
<div class="outline-text-3" id="text-3-1">
<p>
<code>cartesian_product_view</code> presents a view with a value type that represents the cartesian product of the adapted ranges.
</p>

<p>
The name <code>views::cartesian_product</code> denotes a customization point object. Given a pack of subexpressions <code>Es...</code>, the expression <code>views::cartesian_product(Es...)</code> is expression-equivalent to
</p>

<ul class="org-ul">
<li><del style="color: red;">*decay-copy*(views::empty&lt;tuple&lt;&gt;&gt;)</del><ins style="color: green;">views::single(tuple())</ins> if Es is an empty pack,</li>
<li>otherwise, cartesian_product_view&lt;views::all_t&lt;decltype((Es))&gt;&#x2026;&gt;(Es&#x2026;).</li>
</ul>
</div>
</div>
</div>



<div id="outline-container-orgf670c2b" class="outline-2">
<h2 id="orgf670c2b"><span class="section-number-2">4.</span> References</h2>
<div class="outline-text-2" id="text-4">
<p>
Reflector Discussion: [isocpp-lib-ext] zip and cartesian_product base case
<a href="https://lists.isocpp.org/lib-ext/2022/01/22023.php">https://lists.isocpp.org/lib-ext/2022/01/22023.php</a>
</p>

<p>
Twitter: <a href="https://twitter.com/sdowney/status/1482469504248598532">https://twitter.com/sdowney/status/1482469504248598532</a> and ff
</p>

<p>
Empty product - Wikipedia: <a href="https://en.wikipedia.org/wiki/Empty_product">https://en.wikipedia.org/wiki/Empty_product</a>
</p>

<p>
[P2374R3] Sy Brand, Michał Dominiak. 2021-12-13. views::cartesian_product
    <a href="https://wg21.link/p2374r3">https://wg21.link/p2374r3</a>
</p>
</div>
</div>
</div>
</body>
</html>
