On Sat, Jan 24, 2009 at 2:40 AM, Ryan Ingram <span dir="ltr">&lt;<a href="mailto:ryani.spam@gmail.com">ryani.spam@gmail.com</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="Ih2E3d">On Fri, Jan 23, 2009 at 10:49 PM, Thomas Davie &lt;<a href="mailto:tom.davie@gmail.com">tom.davie@gmail.com</a>&gt; wrote:<br>
&gt; Isn&#39;t the point of bottom that it&#39;s the least defined value. &nbsp;Someone above<br>
&gt; made the assertion that for left identity to hold, _|_ `mappend` () must be<br>
&gt; _|_. &nbsp;But, as there is only one value in the Unit type, all values we have<br>
&gt; no information about must surely be that value, so this is akin to saying ()<br>
&gt; `mappend` () must be (), which our definition gives us.<br>
<br>
</div>But _|_ is not ().</blockquote><div><br>Correction: _|_ is not always ().<br><br>I&#39;m no expert in topology, but I think it goes something like this:<br><br>You can interpret partiality in (at least) two ways.&nbsp; The one you&#39;re using is to treat () as the Sierpinski space, which has one open set (which you can think of as ()) and one closed set (as _|_).&nbsp; Bottoms are explicit, and nontermination is an essential part of the calculus.&nbsp;&nbsp; The rest of the topology is generated as follows: each function f : a -&gt; () defines an open and a closed set of as.&nbsp; The open set is { x | f(x) = () }, and the closed set is { x | f(x) = _|_ }.&nbsp;&nbsp; It is a fatal error to ignore _|_ in this semantics.<br>
<br>There is another topology.&nbsp; Here the points are bottom-free values, possibly infinite.&nbsp; It is generated by, for each <i>finite </i>partial value v, choosing the set of all fully-defined x such that v is less defined than x.&nbsp;&nbsp; So, for example, the open set representing Left _|_ in the space Either Bool Bool is { Left True, Left False }, whereas _|_ in this space is { Left True, Left False, Right True, Right False }.<br>
<br>As far as I know, this is a valid topology as well, in which scott-continuity corresponds to topological continuity.&nbsp; However, if you are using this topology, then () = _|_.&nbsp; <br><br>I think the difference is that the latter topology ignores nontermination.&nbsp; When programs terminate, the two interpretations agree.&nbsp; But the latter does not give you any way to prove that something will not terminate.<br>
<br>FWIW, that last paragraph was gross speculation.&nbsp; :-)<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
<br>
For example:<br>
<br>
data Nat = Z | S Finite<br>
<br>
proveFinite :: Nat -&gt; ()<br>
proveFinite Z = ()<br>
proveFinite (S x) = proveFinite x<br>
<br>
infinity :: Nat<br>
infinity = S infinity<br>
<br>
somecode x = case proveFinite x of () -&gt;<br>
something_that_might_rely_on_x_being_finite</blockquote><div><br>If some code relies on a value being finite, the only way it can go wrong if you give it something infinite is not to terminate.&nbsp; This is kind of the point of continuity.<br>
&nbsp;</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
problem = somecode infinity<br>
<br>
If you can pretend that the only value of () is (), and ignore _|_,<br>
you can break invariants. &nbsp;This becomes even more tricky when you have<br>
a single-constructor datatype which holds data relevant to the<br>
typechecker; ignoring _|_ in this case could lead to unsound code.</blockquote><div><br>Except in those cases (in the absense of unsafeCoerce, I&#39;m talking about GADTs etc.) the compiler is checking them for you.<br><br>
Luke<br></div></div>