1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-09 02:24:21 +03:00
inform7/docs/kinds-module/2-kc.html
2020-03-22 10:50:19 +00:00

964 lines
113 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>2/knd</title>
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<nav role="navigation">
<h1><a href="../webs.html">Sources</a></h1>
<ul>
<li><a href="../compiler.html"><b>compiler</b></a></li>
<li><a href="../other.html">other tools</a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul>
<h2>Compiler Webs</h2>
<ul>
<li><a href="../inbuild/index.html">inbuild</a></li>
<li><a href="../inform7/index.html">inform7</a></li>
<li><a href="../inter/index.html">inter</a></li>
</ul>
<h2>Inbuild Modules</h2>
<ul>
<li><a href="../inbuild-module/index.html">inbuild</a></li>
<li><a href="../arch-module/index.html">arch</a></li>
<li><a href="../words-module/index.html">words</a></li>
<li><a href="../syntax-module/index.html">syntax</a></li>
<li><a href="../html-module/index.html">html</a></li>
</ul>
<h2>Inform7 Modules</h2>
<ul>
<li><a href="../core-module/index.html">core</a></li>
<li><a href="../problems-module/index.html">problems</a></li>
<li><a href="../inflections-module/index.html">inflections</a></li>
<li><a href="../linguistics-module/index.html">linguistics</a></li>
<li><a href="../kinds-module/index.html">kinds</a></li>
<li><a href="../if-module/index.html">if</a></li>
<li><a href="../multimedia-module/index.html">multimedia</a></li>
<li><a href="../index-module/index.html">index</a></li>
</ul>
<h2>Inter Modules</h2>
<ul>
<li><a href="../inter-module/index.html">inter</a></li>
<li><a href="../building-module/index.html">building</a></li>
<li><a href="../codegen-module/index.html">codegen</a></li>
</ul>
<h2>Foundation</h2>
<ul>
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of '2/kc' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="../compiler.html">Compiler Modules</a></li><li><a href="index.html">kinds</a></li><li><a href="index.html#2">Chapter 2: Kinds</a></li><li><b>Kind Checking</b></li></ul><p class="purpose">To test whether two kinds are equivalent to each other, or failing that, whether they are compatible with each other.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Definitions</a></li><li><a href="#SP9">&#167;9. Subkinds</a></li><li><a href="#SP14">&#167;14. Kind compatibility</a></li><li><a href="#SP15">&#167;15. Common code</a></li><li><a href="#SP18">&#167;18. Unit tests</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Definitions. </b></p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>We say that a kind K_L is a subkind of K_R if its values can
be used without modification at run-time in code which expects a value of
K_R, and write
K_L &lt;= K_R.
There are many pairs of kinds where neither is compatible with the other:
for instance, it is true neither that rulebook &lt;= text nor that text &lt;= rulebook. So
we're using the notation &lt;= here by analogy with partially-ordered sets
rather than with numbers. The universe of kinds does indeed form a poset
under this relation:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) it is reflexive (K&lt;= K);
</li><li>(b) it is antisymmetric (K&lt;= L and L&lt;= K imply K=L);
</li><li>(c) it is transitive (K&lt;= L and L&lt;= M imply K&lt;= M).
</li></ul>
<p class="inwebparagraph">We test compatibility with the routine <code class="display"><span class="extract">Kinds::Compare::le</span></code>, and for convenience
we also have <code class="display"><span class="extract">Kinds::Compare::eq</span></code> to test equality and <code class="display"><span class="extract">Kinds::Compare::lt</span></code> for the case
when K&lt;= L but K!= L, that is, for K&lt;L. The main aim of this
section is to define those routines.
</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>To say that K_L is compatible with K_R is a weaker statement.
This is the test Inform uses to see whether it will allow K_L values to
be used where K_R values are expected. Clearly if K_L&lt;= K_R then
they must be compatible, but there are other possibilities. For example,
snippets can be used as texts if suitably modified ("cast")
at run-time, but snippet is not &lt;= text. Compatibility lacks the
elegant formal properties of &lt;=: for example, "value" is compatible
with "text" which is in turn compatible with "value".
</p>
<p class="inwebparagraph">This test is performed by <code class="display"><span class="extract">Kinds::Compare::compatible</span></code>. As we will see, the two
relations are similarly defined, and they share most of the code.
</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>A function f on kinds is covariant if K&lt;= L implies f(K)&lt;= f(L),
and contravariant if K&lt;= L implies f(L)&lt;= f(K). Of course there's
no reason a function needs to be either, but the ones provided by our
kind constructors (such "list of", which maps K to list of K) always are.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">COVARIANT</span><span class="plain"> 1</span>
<span class="definitionkeyword">define</span> <span class="constant">CONTRAVARIANT</span><span class="plain"> -1</span>
</pre>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. </b>Kind checking can happen for many reasons, but the most difficult case
occurs when matching phrase prototypes (a task carried out by the main
specification matcher in the next chapter). This is difficult because
it involves kind variables:
</p>
<blockquote>
<p>To add (new entry - K) to (L - list of values of kind K) ...</p>
</blockquote>
<p class="inwebparagraph">This matches "add 23 to L" if "L" is a list of numbers, but not if it
is a list of times.
</p>
<p class="inwebparagraph">Since kind variables can be changed only when matching phrase prototypes,
and this is not a recursive process, we can store the current definitions
of A to Z in a single array.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">MAX_KIND_VARIABLES</span><span class="plain"> 27 </span> <span class="comment">we number them from 1 (A) to 26 (Z)</span>
</pre>
<pre class="display">
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">values_of_kind_variables</span><span class="plain">[</span><span class="constant">MAX_KIND_VARIABLES</span><span class="plain">];</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>In theory the kind-checker only needs to read the values of A to Z, not
to write them. If Q is currently equal to "number", then it should check
kinds against Q exactly as if it were checking against "number". It can
indeed do this &mdash; that's the <code class="display"><span class="extract">MATCH_KIND_VARIABLES_AS_VALUES</span></code> mode. It can
also ignore the values of kind variables and treat them as names, so that
Q matches only against Q, regardless of its current value; that's the
<code class="display"><span class="extract">MATCH_KIND_VARIABLES_AS_SYMBOLS</span></code> mode. Or it can match anything
against Q, which is <code class="display"><span class="extract">MATCH_KIND_VARIABLES_AS_UNIVERSAL</span></code> mode.
</p>
<p class="inwebparagraph">More interestingly, the kind-checker can also set the values of A to Z.
This is convenient since checking their correctness is more or less the same
thing as inferring what they seem to be in a given situation. So this is
<code class="display"><span class="extract">MATCH_KIND_VARIABLES_INFERRING_VALUES</span></code> mode.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">MATCH_KIND_VARIABLES_AS_SYMBOLS</span><span class="plain"> 0</span>
<span class="definitionkeyword">define</span> <span class="constant">MATCH_KIND_VARIABLES_INFERRING_VALUES</span><span class="plain"> 1</span>
<span class="definitionkeyword">define</span> <span class="constant">MATCH_KIND_VARIABLES_AS_VALUES</span><span class="plain"> 2</span>
<span class="definitionkeyword">define</span> <span class="constant">MATCH_KIND_VARIABLES_AS_UNIVERSAL</span><span class="plain"> 3</span>
</pre>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">kind_checker_mode</span><span class="plain"> = </span><span class="constant">MATCH_KIND_VARIABLES_AS_SYMBOLS</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b>When the kind-checker does choose a value for a variable, it not only
sets the relevant entry in the above array but also creates a note that
this has been done. (If a phrase is correctly matched by the specification
matcher, a linked list of these notes is attached to the results: thus
a match of "add 23 to L" in the example above would produce a successful
result plus a note that K has to be "list of numbers".)
</p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">kind_variable_declaration</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">kv_number</span><span class="plain">; </span> <span class="comment">must be from 1 to 26</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">kv_value</span><span class="plain">; </span> <span class="comment">must be a definite non-<code class="display"><span class="extract">NULL</span></code> kind</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">kind_variable_declaration</span><span class="plain"> *</span><span class="identifier">next</span><span class="plain">;</span>
<span class="identifier">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">kind_variable_declaration</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure kind_variable_declaration is accessed in 2/dmn and here.</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. </b>The following constants will be used to represent the results of kind
checking:
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">ALWAYS_MATCH</span><span class="plain"> 2 </span> <span class="comment">provably correct at compile time</span>
<span class="definitionkeyword">define</span> <span class="constant">SOMETIMES_MATCH</span><span class="plain"> 1 </span> <span class="comment">provably reduced to a check feasible at run-time</span>
<span class="definitionkeyword">define</span> <span class="constant">NEVER_MATCH</span><span class="plain"> 0 </span> <span class="comment">provably incorrect at compile time</span>
<span class="definitionkeyword">define</span> <span class="constant">NO_DECISION_ON_MATCH</span><span class="plain"> -1 </span> <span class="comment">none of the above</span>
</pre>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. Subkinds. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">from</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">to</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::test_kind_relation</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">) == </span><span class="constant">ALWAYS_MATCH</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::lt</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">from</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">to</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::le is used in <a href="#SP12">&#167;12</a>, <a href="#SP18_1">&#167;18.1</a>, <a href="#SP18_2">&#167;18.2</a>, <a href="#SP18_4">&#167;18.4</a>, <a href="#SP18_5">&#167;18.5</a>, <a href="#SP18_6">&#167;18.6</a>, 2/knd (<a href="2-knd.html#SP33">&#167;33</a>, <a href="2-knd.html#SP33_2">&#167;33.2</a>), 2/uk (<a href="2-uk.html#SP17">&#167;17</a>, <a href="2-uk.html#SP29">&#167;29</a>, <a href="2-uk.html#SP30">&#167;30</a>, <a href="2-uk.html#SP33">&#167;33</a>, <a href="2-uk.html#SP35">&#167;35</a>).</p>
<p class="endnote">The function Kinds::Compare::lt is used in <a href="#SP17">&#167;17</a>, 2/knd (<a href="2-knd.html#SP30">&#167;30</a>).</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b>The following determines whether or not two kinds are the same. Clearly
all base kinds are different from each other, but in some programming
languages it's an interesting question whether different sequences of
constructors applied to these bases can ever produce an equivalent kind.
Most of the interesting cases are to do with unions (which Inform
disallows as type unsafe) and records (which Inform supports by its
"combination" operator). For example, is "combination (number, text)"
the same as "combination (text, number)"? One might also consider
whether <code class="display"><span class="extract">-&gt;</span></code> (function mapping) ought to be an associative operation, as
it would be in a language like Haskell which curried all functions.
</p>
<p class="inwebparagraph">At any rate, for Inform the answer is no: every different sequence of kind
constructors produces a different kind.
</p>
<p class="inwebparagraph">With kind variables, we take the "name" approach rather than the
"structural" approach: that is, the kind "X" (a variable) is not equivalent
to the kind "number" even if that's the current value of X.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K1</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K2</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K1</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K2</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">; }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K2</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain"> != </span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;intermediate_result</span><span class="plain">) &amp;&amp; (</span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;intermediate_result</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;intermediate_result</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) &amp;&amp; (</span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;intermediate_result</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;intermediate_result</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::Dimensions::compare_unit_sequences</span><span class="plain">(</span>
<span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;intermediate_result</span><span class="plain">, </span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;intermediate_result</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::get_variable_number</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">) != </span><span class="functiontext">Kinds::get_variable_number</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">MAX_KIND_CONSTRUCTION_ARITY</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::eq is used in <a href="#SP9">&#167;9</a>, <a href="#SP12">&#167;12</a>, <a href="#SP14">&#167;14</a>, <a href="#SP15_1">&#167;15.1</a>, <a href="#SP15_2">&#167;15.2</a>, <a href="#SP18_1">&#167;18.1</a>, <a href="#SP18_2">&#167;18.2</a>, <a href="#SP18_4">&#167;18.4</a>, <a href="#SP18_5">&#167;18.5</a>, <a href="#SP18_6">&#167;18.6</a>, 2/knd (<a href="2-knd.html#SP33">&#167;33</a>), 2/uk (<a href="2-uk.html#SP26">&#167;26</a>, <a href="2-uk.html#SP27">&#167;27</a>, <a href="2-uk.html#SP32">&#167;32</a>), 2/dk (<a href="2-dk.html#SP24_1_2">&#167;24.1.2</a>, <a href="2-dk.html#SP24_3_1">&#167;24.3.1</a>, <a href="2-dk.html#SP24_3_2">&#167;24.3.2</a>), 2/dmn (<a href="2-dmn.html#SP18">&#167;18</a>, <a href="2-dmn.html#SP23">&#167;23</a>, <a href="2-dmn.html#SP24">&#167;24</a>, <a href="2-dmn.html#SP26">&#167;26</a>, <a href="2-dmn.html#SP31">&#167;31</a>, <a href="2-dmn.html#SP32_2_1">&#167;32.2.1</a>, <a href="2-dmn.html#SP32_2_2">&#167;32.2.2</a>, <a href="2-dmn.html#SP40_1">&#167;40.1</a>), 2/fv (<a href="2-fv.html#SP4">&#167;4</a>).</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. </b>It turns out to be useful to be able to "increment" a kind K, by trying to
find the S such that K &lt; S but there is no S' with K&lt;S'&lt;S. This is only
well-defined for kinds of object, and otherwise returns <code class="display"><span class="extract">NULL</span></code>.
</p>
<pre class="display">
<span class="reserved">kind</span><span class="plain"> *</span><span class="functiontext">Kinds::Compare::super</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain">) {</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">KINDS_SUPER</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">KINDS_SUPER</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">);</span>
<span class="plain">#</span><span class="reserved">else</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::super is used in <a href="#SP12">&#167;12</a>, <a href="#SP17">&#167;17</a>, <a href="#SP18_3">&#167;18.3</a>.</p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. </b>The maximum of K_1 and K_2 is by definition the kind M such that
K_1&lt;= M and K_2&lt;= M, and there is no M'&lt;M with the same property.
This is similarly not well-defined in some cases, in which case we simply
return "value" as a safe answer.
</p>
<pre class="display">
<span class="reserved">kind</span><span class="plain"> *</span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K1</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K2</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::FloatingPoint::uses_floating_point</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::FloatingPoint::uses_floating_point</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="functiontext">Kinds::FloatingPoint::real_equivalent</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">), </span><span class="identifier">K2</span><span class="plain">)))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">K2</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::FloatingPoint::uses_floating_point</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::FloatingPoint::uses_floating_point</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="functiontext">Kinds::FloatingPoint::real_equivalent</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">), </span><span class="identifier">K1</span><span class="plain">)))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">K1</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::traverse_kind_poset</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">, </span><span class="identifier">K2</span><span class="plain">, 1);</span>
<span class="plain">}</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="functiontext">Kinds::Compare::traverse_kind_poset</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K1</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K2</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">direction</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K1</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">K2</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K2</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">K1</span><span class="plain">;</span>
<span class="reserved">kind_constructor</span><span class="plain"> *</span><span class="identifier">con</span><span class="plain"> = </span><span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">a1</span><span class="plain"> = </span><span class="functiontext">Kinds::Constructors::arity</span><span class="plain">(</span><span class="identifier">con</span><span class="plain">), </span><span class="identifier">a2</span><span class="plain"> = </span><span class="functiontext">Kinds::Constructors::arity</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">a1</span><span class="plain"> &gt; 0) || (</span><span class="identifier">a2</span><span class="plain"> &gt; 0)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain"> != </span><span class="identifier">con</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">K_value</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">ka</span><span class="plain">[</span><span class="constant">MAX_KIND_CONSTRUCTION_ARITY</span><span class="plain">];</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">a1</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">con</span><span class="plain">-</span><span class="element">&gt;variance</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] == </span><span class="constant">COVARIANT</span><span class="plain">)</span>
<span class="identifier">ka</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="functiontext">Kinds::Compare::traverse_kind_poset</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">direction</span><span class="plain">);</span>
<span class="reserved">else</span>
<span class="identifier">ka</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="functiontext">Kinds::Compare::traverse_kind_poset</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">K2</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], -</span><span class="identifier">direction</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">a1</span><span class="plain"> == 1) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Kinds::unary_construction</span><span class="plain">(</span><span class="identifier">con</span><span class="plain">, </span><span class="identifier">ka</span><span class="plain">[0]);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Kinds::binary_construction</span><span class="plain">(</span><span class="identifier">con</span><span class="plain">, </span><span class="identifier">ka</span><span class="plain">[0], </span><span class="identifier">ka</span><span class="plain">[1]);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">, </span><span class="identifier">K2</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> (</span><span class="identifier">direction</span><span class="plain"> &gt; 0)?</span><span class="identifier">K2</span><span class="plain">:</span><span class="identifier">K1</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">, </span><span class="identifier">K1</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> (</span><span class="identifier">direction</span><span class="plain"> &gt; 0)?</span><span class="identifier">K1</span><span class="plain">:</span><span class="identifier">K2</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">direction</span><span class="plain"> &gt; 0) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">)) &amp;&amp; (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">))) {</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">K</span><span class="plain"> = </span><span class="identifier">K1</span><span class="plain">; </span><span class="identifier">K</span><span class="plain">; </span><span class="identifier">K</span><span class="plain"> = </span><span class="functiontext">Kinds::Compare::super</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">))</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">, </span><span class="identifier">K</span><span class="plain">))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">K</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">K_value</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::max is used in <a href="#SP13">&#167;13</a>, <a href="#SP18_5">&#167;18.5</a>, <a href="#SP18_6">&#167;18.6</a>.</p>
<p class="endnote">The function Kinds::Compare::traverse_kind_poset appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. </b>A variation on this is the accumulated maximum, used for example when
inferring the kinds of table columns by looking through entries one by one.
This is needed because the empty list has kind "list of values", and yet
should be considered for these purposes as a subkind of "list of texts".
</p>
<pre class="display">
<span class="reserved">kind</span><span class="plain"> *</span><span class="functiontext">Kinds::Compare::accumulative_max</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K1</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K2</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::Behaviour::definite</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">) == </span><span class="identifier">TRUE</span><span class="plain">) &amp;&amp; (</span><span class="functiontext">Kinds::Behaviour::definite</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::Compare::compatible</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">, </span><span class="identifier">K1</span><span class="plain">) == </span><span class="constant">ALWAYS_MATCH</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">K1</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::Behaviour::definite</span><span class="plain">(</span><span class="identifier">K2</span><span class="plain">) == </span><span class="identifier">TRUE</span><span class="plain">) &amp;&amp; (</span><span class="functiontext">Kinds::Behaviour::definite</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::Compare::compatible</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">, </span><span class="identifier">K2</span><span class="plain">) == </span><span class="constant">ALWAYS_MATCH</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">K2</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">K1</span><span class="plain">, </span><span class="identifier">K2</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::accumulative_max appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. Kind compatibility. </b>Now for a more interesting question. If K_F and K_T are kinds, what
values do they have in common? <code class="display"><span class="extract">Kinds::Compare::compatible</span></code> returns
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">ALWAYS_MATCH</span></code> if a value of kind K_F can always be used when a value
of kind K_T is expected,
</li><li>(b) <code class="display"><span class="extract">SOMETIMES_MATCH</span></code> if it sometimes can, but this needs to be protected
by run-time checking in individual cases, or
</li><li>(c) <code class="display"><span class="extract">NEVER_MATCH</span></code> if it never can.
</li></ul>
<p class="inwebparagraph">For example, a value of kind "vehicle" can always be used when a value of
kind "object" is expected; a value of kind "object" can only sometimes
be used when a "vehicle" is expected, and any attempt to use it should
be guarded by run-time checking that is indeed a vehicle; a value of kind
"number" can never be used when a "scene" is expected.
</p>
<p class="inwebparagraph">The outer routine is just a logging mechanism for the real routine. Cases
where K_F = K_T are frequent and not interesting enough to be logged.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::compatible</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">from</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">to</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">KIND_CHECKING</span><span class="plain">, </span><span class="string">"(Is the kind $u compatible with $u?"</span><span class="plain">, </span><span class="identifier">from</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">);</span>
<span class="reserved">switch</span><span class="plain">(</span><span class="functiontext">Kinds::Compare::test_kind_relation</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">)) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">: </span><span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">KIND_CHECKING</span><span class="plain">, </span><span class="string">" No)\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">: </span><span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">KIND_CHECKING</span><span class="plain">, </span><span class="string">" Yes)\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">SOMETIMES_MATCH</span><span class="plain">: </span><span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">KIND_CHECKING</span><span class="plain">, </span><span class="string">" Sometimes)\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">SOMETIMES_MATCH</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"bad return value from Kinds::Compare::compatible"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::compatible is used in <a href="#SP13">&#167;13</a>, <a href="#SP17">&#167;17</a>, <a href="#SP18_2">&#167;18.2</a>.</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. Common code. </b>So the following routine tests &lt;= if <code class="display"><span class="extract">comp</span></code> is <code class="display"><span class="extract">FALSE</span></code>, returning
<code class="display"><span class="extract">ALWAYS_MATCH</span></code> if and only if &lt;= holds; and otherwise it tests compatibility.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::test_kind_relation</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">from</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">to</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">comp</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::get_variable_number</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">) &gt; 0) {</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">var_k</span><span class="plain"> = </span><span class="identifier">to</span><span class="plain">, *</span><span class="identifier">other_k</span><span class="plain"> = </span><span class="identifier">from</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Deal separately with matches against kind variables</span> <span class="cwebmacronumber">15.6</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::get_variable_number</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">) &gt; 0) {</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">var_k</span><span class="plain"> = </span><span class="identifier">from</span><span class="plain">, *</span><span class="identifier">other_k</span><span class="plain"> = </span><span class="identifier">to</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Deal separately with matches against kind variables</span> <span class="cwebmacronumber">15.6</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
&lt;<span class="cwebmacro">Deal separately with the sayability of lists</span> <span class="cwebmacronumber">15.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Deal separately with the special role of value</span> <span class="cwebmacronumber">15.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Deal separately with the special role of the unknown kind</span> <span class="cwebmacronumber">15.3</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Deal separately with compatibility within the objects hierarchy</span> <span class="cwebmacronumber">15.4</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">The general case of compatibility</span> <span class="cwebmacronumber">15.5</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::test_kind_relation is used in <a href="#SP9">&#167;9</a>, <a href="#SP14">&#167;14</a>, <a href="#SP15_1">&#167;15.1</a>, <a href="#SP15_5">&#167;15.5</a>, <a href="#SP15_6_1">&#167;15.6.1</a>, <a href="#SP15_6_2">&#167;15.6.2</a>.</p>
<p class="inwebparagraph"><a id="SP15_1"></a><b>&#167;15.1. </b>A list is sayable if and only if its contents are.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Deal separately with the sayability of lists</span> <span class="cwebmacronumber">15.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::get_construct</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">) == </span><span class="identifier">CON_list_of</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">, </span><span class="identifier">K_sayable_value</span><span class="plain">)))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::test_kind_relation</span><span class="plain">(</span>
<span class="functiontext">Kinds::unary_construction_material</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">), </span><span class="identifier">K_sayable_value</span><span class="plain">, </span><span class="identifier">comp</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15">&#167;15</a>.</p>
<p class="inwebparagraph"><a id="SP15_2"></a><b>&#167;15.2. </b>"Value" is special because, for every kind K, we have K&lt;= V &mdash; it
represents a supremum in our partially ordered set of kinds.
</p>
<p class="inwebparagraph">But it is also used in Inform to mark places where type safety has
deliberately been put aside. For compatibility purposes, then, giving
something the kind "value" is a way of saying that we don't care what its
kind is, and we always allow the usage. So "value" is compatible with
everything &mdash; which is one reason compatibility isn't a partial ordering:
"value" is compatible with "number" and vice versa, yet they are
different kinds.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Deal separately with the special role of value</span> <span class="cwebmacronumber">15.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">, </span><span class="identifier">K_value</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">comp</span><span class="plain">) &amp;&amp; (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">, </span><span class="identifier">K_value</span><span class="plain">))) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15">&#167;15</a>.</p>
<p class="inwebparagraph"><a id="SP15_3"></a><b>&#167;15.3. </b><code class="display"><span class="extract">NULL</span></code> as a kind means "unknown". It's compatible only with itself
and, of course, "value".
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Deal separately with the special role of the unknown kind</span> <span class="cwebmacronumber">15.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">to</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) &amp;&amp; (</span><span class="identifier">from</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">to</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">from</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15">&#167;15</a>.</p>
<p class="inwebparagraph"><a id="SP15_4"></a><b>&#167;15.4. </b>Here both our kinds are &lt;= "object".
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Deal separately with compatibility within the objects hierarchy</span> <span class="cwebmacronumber">15.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">KINDS_COMPATIBLE</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">m</span><span class="plain"> = </span><span class="identifier">KINDS_COMPATIBLE</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">m</span><span class="plain"> != </span><span class="constant">NO_DECISION_ON_MATCH</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">m</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">endif</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15">&#167;15</a>.</p>
<p class="inwebparagraph"><a id="SP15_5"></a><b>&#167;15.5. </b><code class="display">
&lt;<span class="cwebmacrodefn">The general case of compatibility</span> <span class="cwebmacronumber">15.5</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Constructors::compatible</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain">, </span><span class="identifier">comp</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">f_a</span><span class="plain"> = </span><span class="functiontext">Kinds::Constructors::arity</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">t_a</span><span class="plain"> = </span><span class="functiontext">Kinds::Constructors::arity</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">arity</span><span class="plain"> = (</span><span class="identifier">f_a</span><span class="plain"> &lt; </span><span class="identifier">t_a</span><span class="plain">)?</span><span class="identifier">f_a</span><span class="plain">:</span><span class="identifier">t_a</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">, </span><span class="identifier">o</span><span class="plain"> = </span><span class="constant">ALWAYS_MATCH</span><span class="plain">, </span><span class="identifier">this_o</span><span class="plain"> = </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">arity</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Constructors::variance</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">) == </span><span class="constant">COVARIANT</span><span class="plain">)</span>
<span class="identifier">this_o</span><span class="plain"> = </span><span class="functiontext">Kinds::Compare::test_kind_relation</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">to</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">comp</span><span class="plain">);</span>
<span class="reserved">else</span>
<span class="identifier">this_o</span><span class="plain"> = </span><span class="functiontext">Kinds::Compare::test_kind_relation</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">from</span><span class="plain">-</span><span class="element">&gt;kc_args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">comp</span><span class="plain">);</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">this_o</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">: </span><span class="identifier">o</span><span class="plain"> = </span><span class="identifier">this_o</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">SOMETIMES_MATCH</span><span class="plain">: </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">o</span><span class="plain"> != </span><span class="constant">NEVER_MATCH</span><span class="plain">) </span><span class="identifier">o</span><span class="plain"> = </span><span class="identifier">this_o</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">o</span><span class="plain"> == </span><span class="constant">SOMETIMES_MATCH</span><span class="plain">) &amp;&amp; (</span><span class="identifier">to</span><span class="plain">-</span><span class="element">&gt;construct</span><span class="plain"> != </span><span class="identifier">CON_list_of</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">o</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15">&#167;15</a>.</p>
<p class="inwebparagraph"><a id="SP15_6"></a><b>&#167;15.6. </b>Recall that kind variables are identified by a number in the range 1 ("A")
to 26 ("Z"), and that it is also possible to assign them a domain, or a
"declaration". This marks that they are free to take on a value, within
that domain. For example, in
</p>
<blockquote>
<p>To add (new entry - K) to (L - list of values of kind K) ...</p>
</blockquote>
<p class="inwebparagraph">the first appearance of "K" will be an ordinary use of a kind variable,
whereas the second has the declaration "value" &mdash; meaning that it can
become any kind matching "value". (It could alternatively have had a
more restrictive declaration like "arithmetic value".)
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Deal separately with matches against kind variables</span> <span class="cwebmacronumber">15.6</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">kind_checker_mode</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">MATCH_KIND_VARIABLES_AS_SYMBOLS</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::get_variable_number</span><span class="plain">(</span><span class="identifier">other_k</span><span class="plain">) ==</span>
<span class="functiontext">Kinds::get_variable_number</span><span class="plain">(</span><span class="identifier">var_k</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">MATCH_KIND_VARIABLES_AS_UNIVERSAL</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="reserved">default</span><span class="plain">: {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">vn</span><span class="plain"> = </span><span class="functiontext">Kinds::get_variable_number</span><span class="plain">(</span><span class="identifier">var_k</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::get_variable_stipulation</span><span class="plain">(</span><span class="identifier">var_k</span><span class="plain">))</span>
&lt;<span class="cwebmacro">Act on a declaration usage, where inference is allowed</span> <span class="cwebmacronumber">15.6.1</span>&gt;
<span class="reserved">else</span>
&lt;<span class="cwebmacro">Act on an ordinary usage, where inference is not allowed</span> <span class="cwebmacronumber">15.6.2</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15">&#167;15</a> (twice).</p>
<p class="inwebparagraph"><a id="SP15_6_1"></a><b>&#167;15.6.1. </b>When the specification matcher works on matching text such as
</p>
<blockquote>
<p>add 23 to the scores list;</p>
</blockquote>
<p class="inwebparagraph">it works through the prototype:
</p>
<blockquote>
<p>To add (new entry - K) to (L - list of values of kind K) ...</p>
</blockquote>
<p class="inwebparagraph">in two passes. On the first pass, it tries to match the tokens "23" and
"scores list" against "K" and "list of values of kind K" respectively
in <code class="display"><span class="extract">MATCH_KIND_VARIABLES_INFERRING_VALUES</span></code> mode; on the second pass, it
does the same in <code class="display"><span class="extract">MATCH_KIND_VARIABLES_AS_VALUES</span></code> mode. In this example,
on the first pass we infer (from the kind of "scores list", which is
indeed a list of numbers) that K must be "number"; on the second pass
we verify that "23" is a K.
</p>
<p class="inwebparagraph">The following shows what happens matching "values of kind K", which is
a declaration usage of the variable K.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Act on a declaration usage, where inference is allowed</span> <span class="cwebmacronumber">15.6.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">kind_checker_mode</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">MATCH_KIND_VARIABLES_INFERRING_VALUES</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::test_kind_relation</span><span class="plain">(</span><span class="identifier">other_k</span><span class="plain">,</span>
<span class="functiontext">Kinds::get_variable_stipulation</span><span class="plain">(</span><span class="identifier">var_k</span><span class="plain">), </span><span class="identifier">comp</span><span class="plain">) != </span><span class="constant">ALWAYS_MATCH</span><span class="plain">)</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">KIND_CHECKING</span><span class="plain">, </span><span class="string">"Inferring kind variable %d from $u (declaration $u)\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">vn</span><span class="plain">, </span><span class="identifier">other_k</span><span class="plain">, </span><span class="functiontext">Kinds::get_variable_stipulation</span><span class="plain">(</span><span class="identifier">var_k</span><span class="plain">));</span>
<span class="identifier">values_of_kind_variables</span><span class="plain">[</span><span class="identifier">vn</span><span class="plain">] = </span><span class="identifier">other_k</span><span class="plain">;</span>
<span class="reserved">kind_variable_declaration</span><span class="plain"> *</span><span class="identifier">kvd</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">kind_variable_declaration</span><span class="plain">);</span>
<span class="identifier">kvd</span><span class="plain">-</span><span class="element">&gt;kv_number</span><span class="plain"> = </span><span class="identifier">vn</span><span class="plain">;</span>
<span class="identifier">kvd</span><span class="plain">-</span><span class="element">&gt;kv_value</span><span class="plain"> = </span><span class="identifier">other_k</span><span class="plain">;</span>
<span class="identifier">kvd</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">MATCH_KIND_VARIABLES_AS_VALUES</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15_6">&#167;15.6</a>.</p>
<p class="inwebparagraph"><a id="SP15_6_2"></a><b>&#167;15.6.2. </b>Whereas this is what happens when matching just "K". On the inference pass,
we always make a match, which is legitimate because we know we are going to
make a value-checking pass later.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Act on an ordinary usage, where inference is not allowed</span> <span class="cwebmacronumber">15.6.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">kind_checker_mode</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">MATCH_KIND_VARIABLES_INFERRING_VALUES</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">MATCH_KIND_VARIABLES_AS_VALUES</span><span class="plain">:</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">KIND_CHECKING</span><span class="plain">, </span><span class="string">"Checking $u against kind variable %d (=$u)\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">other_k</span><span class="plain">, </span><span class="identifier">vn</span><span class="plain">, </span><span class="identifier">values_of_kind_variables</span><span class="plain">[</span><span class="identifier">vn</span><span class="plain">]);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::test_kind_relation</span><span class="plain">(</span><span class="identifier">other_k</span><span class="plain">, </span><span class="identifier">values_of_kind_variables</span><span class="plain">[</span><span class="identifier">vn</span><span class="plain">], </span><span class="identifier">comp</span><span class="plain">) == </span><span class="constant">NEVER_MATCH</span><span class="plain">)</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">;</span>
<span class="reserved">else</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">ALWAYS_MATCH</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15_6">&#167;15.6</a>.</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::show_variables</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Variables: "</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=1; </span><span class="identifier">i</span><span class="plain">&lt;=26; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="identifier">values_of_kind_variables</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">];</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">continue</span><span class="plain">;</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"%c=$u "</span><span class="plain">, </span><span class="character">'A'</span><span class="plain">+</span><span class="identifier">i</span><span class="plain">-1, </span><span class="identifier">K</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::show_frame_variables</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">shown</span><span class="plain"> = 0;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=1; </span><span class="identifier">i</span><span class="plain">&lt;=26; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="identifier">KIND_VARIABLE_FROM_CONTEXT</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">shown</span><span class="plain">++ == 0) </span><span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"Stack frame uses kind variables: "</span><span class="plain">);</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"%c=$u "</span><span class="plain">, </span><span class="character">'A'</span><span class="plain">+</span><span class="identifier">i</span><span class="plain">-1, </span><span class="identifier">K</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">shown</span><span class="plain"> == 0) </span><span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"Stack frame sets no kind variables"</span><span class="plain">);</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::show_variables appears nowhere else.</p>
<p class="endnote">The function Kinds::Compare::show_frame_variables appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::make_subkind</span><span class="plain">(</span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">sub</span><span class="plain">, </span><span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">super</span><span class="plain">) {</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">PROTECTED_MODEL_PROCEDURE</span>
<span class="identifier">PROTECTED_MODEL_PROCEDURE</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">sub</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Tried to set kind to $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">super</span><span class="plain">);</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"Tried to set the kind of a null kind"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::lt</span><span class="plain">(</span><span class="identifier">sub</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">NEW_SUBKIND_NOTIFY</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">NEW_SUBKIND_NOTIFY</span><span class="plain">(</span><span class="identifier">sub</span><span class="plain">, </span><span class="identifier">super</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">existing</span><span class="plain"> = </span><span class="functiontext">Kinds::Compare::super</span><span class="plain">(</span><span class="identifier">sub</span><span class="plain">);</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::compatible</span><span class="plain">(</span><span class="identifier">existing</span><span class="plain">, </span><span class="identifier">super</span><span class="plain">)) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">NEVER_MATCH</span><span class="plain">:</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Tried to make $u a kind of $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">sub</span><span class="plain">, </span><span class="identifier">super</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">problem_count</span><span class="plain"> == 0)</span>
<span class="identifier">KINDS_PROBLEM_HANDLER</span><span class="plain">(</span><span class="constant">KindUnalterable_KINDERROR</span><span class="plain">,</span>
<span class="functiontext">Kinds::Behaviour::get_superkind_set_at</span><span class="plain">(</span><span class="identifier">sub</span><span class="plain">), </span><span class="identifier">super</span><span class="plain">, </span><span class="identifier">existing</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">SOMETIMES_MATCH</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">KINDS_TEST_WITHIN</span><span class="plain">(</span><span class="identifier">super</span><span class="plain">, </span><span class="identifier">sub</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">problem_count</span><span class="plain"> == 0)</span>
<span class="identifier">KINDS_PROBLEM_HANDLER</span><span class="plain">(</span><span class="constant">KindsCircular_KINDERROR</span><span class="plain">,</span>
<span class="functiontext">Kinds::Behaviour::get_superkind_set_at</span><span class="plain">(</span><span class="identifier">super</span><span class="plain">), </span><span class="identifier">super</span><span class="plain">, </span><span class="identifier">existing</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">KINDS_MOVE_WITHIN</span><span class="plain">(</span><span class="identifier">sub</span><span class="plain">, </span><span class="identifier">super</span><span class="plain">);</span>
<span class="functiontext">Kinds::Behaviour::set_superkind_set_at</span><span class="plain">(</span><span class="identifier">sub</span><span class="plain">, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">KIND_CHANGES</span><span class="plain">, </span><span class="string">"Making $u a subkind of $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">sub</span><span class="plain">, </span><span class="identifier">super</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::make_subkind appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP18"></a><b>&#167;18. Unit tests. </b>Some internal test cases check that the hierarchy of kinds is behaving as we expect:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Kinds::Compare::log_poset</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">) {</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">n</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> 1: </span>&lt;<span class="cwebmacro">Display the subkind relation of base kinds</span> <span class="cwebmacronumber">18.1</span>&gt;<span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 2: </span>&lt;<span class="cwebmacro">Display the compatibility relation of base kinds</span> <span class="cwebmacronumber">18.2</span>&gt;<span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 3: </span>&lt;<span class="cwebmacro">Display the results of the superkind function</span> <span class="cwebmacronumber">18.3</span>&gt;<span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 4: </span>&lt;<span class="cwebmacro">Check for poset violations</span> <span class="cwebmacronumber">18.4</span>&gt;<span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 5: </span>&lt;<span class="cwebmacro">Check the maximum function</span> <span class="cwebmacronumber">18.5</span>&gt;<span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 6: </span>&lt;<span class="cwebmacro">Some miscellaneous tests with a grab bag of kinds</span> <span class="cwebmacronumber">18.6</span>&gt;<span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Kinds::Compare::log_poset appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP18_1"></a><b>&#167;18.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Display the subkind relation of base kinds</span> <span class="cwebmacronumber">18.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"The subkind relation on (base) kinds:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">, *</span><span class="identifier">B</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = 0;</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">)) &amp;&amp; (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain">++ == 0) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$u &lt;= "</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">); </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">", "</span><span class="plain">);</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$u"</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> &gt; 0) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP18_2"></a><b>&#167;18.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Display the compatibility relation of base kinds</span> <span class="cwebmacronumber">18.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"The (always) compatibility relation on (base) kinds, where it differs from &lt;=:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">, *</span><span class="identifier">B</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = 0;</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::Compare::compatible</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">) == </span><span class="constant">ALWAYS_MATCH</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">K_value</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain">++ == 0) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$u --&gt; "</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">); </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">", "</span><span class="plain">);</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$u"</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> &gt; 0) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP18_3"></a><b>&#167;18.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Display the results of the superkind function</span> <span class="cwebmacronumber">18.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"The superkind function applied to base kinds:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">, *</span><span class="identifier">B</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">) {</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">B</span><span class="plain"> = </span><span class="identifier">A</span><span class="plain">; </span><span class="identifier">B</span><span class="plain">; </span><span class="identifier">B</span><span class="plain"> = </span><span class="functiontext">Kinds::Compare::super</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">))</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$u -&gt; "</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">);</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP18_4"></a><b>&#167;18.4. </b><code class="display">
&lt;<span class="cwebmacrodefn">Check for poset violations</span> <span class="cwebmacronumber">18.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Looking for partially ordered set violations.\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">, *</span><span class="identifier">B</span><span class="plain">, *</span><span class="identifier">C</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Reflexivity violated: $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">);</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">)) &amp;&amp; (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">)) &amp;&amp; (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">))</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Antisymmetry violated: $u, $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">);</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">)) &amp;&amp; (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">)) &amp;&amp; (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">))</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Transitivity violated: $u, $u, $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP18_5"></a><b>&#167;18.5. </b><code class="display">
&lt;<span class="cwebmacrodefn">Check the maximum function</span> <span class="cwebmacronumber">18.5</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Looking for maximum violations.\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">, *</span><span class="identifier">B</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">), </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">)) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Fail symmetry: max($u, $u) = $u, but max($u, $u) = $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">, </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">), </span><span class="identifier">B</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">, </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">));</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">)) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Fail maximality(A): max($u, $u) = $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">, </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">));</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">, </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">)) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Fail maximality(B): max($u, $u) = $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">, </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">B</span><span class="plain">));</span>
<span class="identifier">LOOP_OVER_BASE_KINDS</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">), </span><span class="identifier">A</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Fail: max($u, $u) = $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">A</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">, </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">));</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP18_6"></a><b>&#167;18.6. </b></p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">SIZE_OF_GRAB_BAG</span><span class="plain"> 11</span>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Some miscellaneous tests with a grab bag of kinds</span> <span class="cwebmacronumber">18.6</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">tests</span><span class="plain">[</span><span class="constant">SIZE_OF_GRAB_BAG</span><span class="plain">];</span>
<span class="identifier">tests</span><span class="plain">[0] = </span><span class="identifier">K_number</span><span class="plain">;</span>
<span class="identifier">tests</span><span class="plain">[1] = </span><span class="identifier">K_container</span><span class="plain">;</span>
<span class="identifier">tests</span><span class="plain">[2] = </span><span class="identifier">K_door</span><span class="plain">;</span>
<span class="identifier">tests</span><span class="plain">[3] = </span><span class="identifier">K_thing</span><span class="plain">;</span>
<span class="identifier">tests</span><span class="plain">[4] = </span><span class="functiontext">Kinds::unary_construction</span><span class="plain">(</span><span class="identifier">CON_list_of</span><span class="plain">, </span><span class="identifier">K_container</span><span class="plain">);</span>
<span class="identifier">tests</span><span class="plain">[5] = </span><span class="functiontext">Kinds::unary_construction</span><span class="plain">(</span><span class="identifier">CON_list_of</span><span class="plain">, </span><span class="identifier">K_door</span><span class="plain">);</span>
<span class="identifier">tests</span><span class="plain">[6] = </span><span class="functiontext">Kinds::unary_construction</span><span class="plain">(</span><span class="identifier">CON_list_of</span><span class="plain">, </span><span class="identifier">K_person</span><span class="plain">);</span>
<span class="identifier">tests</span><span class="plain">[7] = </span><span class="functiontext">Kinds::unary_construction</span><span class="plain">(</span><span class="identifier">CON_list_of</span><span class="plain">, </span><span class="identifier">K_thing</span><span class="plain">);</span>
<span class="identifier">tests</span><span class="plain">[8] = </span><span class="functiontext">Kinds::binary_construction</span><span class="plain">(</span><span class="identifier">CON_phrase</span><span class="plain">,</span>
<span class="functiontext">Kinds::binary_construction</span><span class="plain">(</span><span class="identifier">CON_TUPLE_ENTRY</span><span class="plain">, </span><span class="identifier">K_door</span><span class="plain">, </span><span class="identifier">K_nil</span><span class="plain">), </span><span class="identifier">K_object</span><span class="plain">);</span>
<span class="identifier">tests</span><span class="plain">[9] = </span><span class="functiontext">Kinds::binary_construction</span><span class="plain">(</span><span class="identifier">CON_phrase</span><span class="plain">,</span>
<span class="functiontext">Kinds::binary_construction</span><span class="plain">(</span><span class="identifier">CON_TUPLE_ENTRY</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">, </span><span class="identifier">K_nil</span><span class="plain">), </span><span class="identifier">K_door</span><span class="plain">);</span>
<span class="identifier">tests</span><span class="plain">[10] = </span><span class="functiontext">Kinds::binary_construction</span><span class="plain">(</span><span class="identifier">CON_phrase</span><span class="plain">,</span>
<span class="functiontext">Kinds::binary_construction</span><span class="plain">(</span><span class="identifier">CON_TUPLE_ENTRY</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">, </span><span class="identifier">K_nil</span><span class="plain">), </span><span class="identifier">K_object</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">, </span><span class="identifier">j</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">SIZE_OF_GRAB_BAG</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="reserved">for</span><span class="plain"> (</span><span class="identifier">j</span><span class="plain">=</span><span class="identifier">i</span><span class="plain">+1; </span><span class="identifier">j</span><span class="plain">&lt;</span><span class="constant">SIZE_OF_GRAB_BAG</span><span class="plain">; </span><span class="identifier">j</span><span class="plain">++) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">])) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$u &lt;= $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">]);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">], </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">])) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$u &lt;= $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">], </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]);</span>
<span class="reserved">kind</span><span class="plain"> *</span><span class="identifier">M</span><span class="plain"> = </span><span class="functiontext">Kinds::Compare::max</span><span class="plain">(</span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">]);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">M</span><span class="plain">, </span><span class="identifier">K_value</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"max($u, $u) = $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">tests</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">], </span><span class="identifier">M</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">#</span><span class="identifier">endif</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP18">&#167;18</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="2-knd.html">Back to 'Kinds'</a></li><li><a href="2-kc2.html">Continue with 'Kind Constructors'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</main>
</body>
</html>