Hi,<br><br>One could also argue that a good email client should automatically hide long quotes. In fact, I guess many people are not even aware of the problem because their client does this.<br><br><br>Cheers,<br>Pedro<br>

<br><div class="gmail_quote">On Thu, Jan 19, 2012 at 11:14, Malcolm Wallace <span dir="ltr">&lt;<a href="mailto:malcolm.wallace@me.com">malcolm.wallace@me.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

Sorry to pick on your post in particular Matthew, but I have been seeing a lot of this on the Haskell lists lately.<br>
<br>
I find it completely unreasonable for a reply to a very long post to quote the entire text, only to add a single line at the bottom (or worse, embedded in the middle somewhere).  In this case, there are 7 pages of quotation before your one-sentence contribution.  (That is on my laptop.  I dread to think how many pages it represents on a smartphone screen...)  Usually, if I need to scroll even to the second page-worth of quotation and have still not found any new text, I now just delete the post without reading it.<br>


<br>
It is a failure to communicate well, on the part of the writer who values their own time more highly than that of their intended readers.  Even the much-maligned top-posting style, as forced upon Outlook users (and as I am doing right here), is preferable to the failure to trim, or to get to the point quickly.  My inbox has &gt;1600 unread messages in it, and life is just too short.  So I offer this plea as a constructive social suggestion - if you want your ideas to reach their intended audience, don&#39;t annoy them before they have even seen what you want to say.<br>


<br>
Regards,<br>
    Malcolm<br>
<br>
<br>
On 15 Jan 2012, at 20:33, Matthew Farkas-Dyck wrote:<br>
<br>
&gt; On 13/01/2012, Simon Peyton-Jones &lt;<a href="mailto:simonpj@microsoft.com">simonpj@microsoft.com</a>&gt; wrote:<br>
&gt;&gt; Thanks to Greg for leading the records debate.  I apologise that I<br>
&gt;&gt; don&#39;t have enough bandwidth to make more than an occasional<br>
&gt;&gt; contribution.  Greg&#39;s new wiki page, and the discussion so far has<br>
&gt;&gt; clarified my thinking, and this message tries to express that new<br>
&gt;&gt; clarity.  I put a conclusion at the end.<br>
&gt;&gt;<br>
&gt;&gt; Simon<br>
&gt;&gt;<br>
&gt;&gt; Overview<br>
&gt;&gt; ~~~~~~~~<br>
&gt;&gt; It has become clear that there are two elements to pretty much all the<br>
&gt;&gt; proposals we have on the table.  Suppose we have two types, &#39;S&#39; and &#39;T&#39;,<br>
&gt;&gt; both with a field &#39;f&#39;, and you want to select field &#39;f&#39; from a record &#39;r&#39;.<br>
&gt;&gt; Somehow you have to disambiguate which &#39;f&#39; you mean.<br>
&gt;&gt;<br>
&gt;&gt; (Plan A) Disambiguate using qualified names.  To select field f, say<br>
&gt;&gt;        (S.f r) or (T.f r) respectively.<br>
&gt;&gt;<br>
&gt;&gt; (Plan B) Disambiguate using types. This approach usually implies<br>
&gt;&gt; dot-notation.<br>
&gt;&gt;         If  (r::S), then (r.f) uses the &#39;f&#39; from &#39;S&#39;, and similarly if<br>
&gt;&gt; (r::T).<br>
&gt;&gt;<br>
&gt;&gt; Note that<br>
&gt;&gt;<br>
&gt;&gt; * The Frege-derived records proposal (FDR), uses both (A) and (B)<br>
&gt;&gt;  <a href="http://hackage.haskell.org/trac/ghc/wiki/Records/NameSpacing" target="_blank">http://hackage.haskell.org/trac/ghc/wiki/Records/NameSpacing</a><br>
&gt;&gt;<br>
&gt;&gt; * The Simple Overloaded Record Fields (SORF) proposal uses only (B)<br>
&gt;&gt;  <a href="http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields" target="_blank">http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields</a><br>
&gt;&gt;<br>
&gt;&gt; * The Type Directed Name Resolution proposal (TDNR) uses only (B)<br>
&gt;&gt;<br>
&gt;&gt; <a href="http://hackage.haskell.org/trac/haskell-prime/wiki/TypeDirectedNameResolution" target="_blank">http://hackage.haskell.org/trac/haskell-prime/wiki/TypeDirectedNameResolution</a><br>
&gt;&gt;<br>
&gt;&gt; I know of no proposal that advocates only (A).  It seems that we are agreed<br>
&gt;&gt; that we must make use of types to disambigute common cases.<br>
&gt;&gt;<br>
&gt;&gt; Complexities of (Plan B)<br>
&gt;&gt; ~~~~~~~~~~~~~~~~~~~~~~~~<br>
&gt;&gt; Proposal (Plan B) sounds innocent enough.  But I promise you, it isn&#39;t.<br>
&gt;&gt; There has ben some mention of the &quot;left-to-right&quot; bias of Frege type<br>
&gt;&gt; inference engine; indeed the wohle explanation of which programs are<br>
&gt;&gt; accepted and which are rejected, inherently involves an understanding<br>
&gt;&gt; of the type inference algorithm.  This is a Very Bad Thing when the<br>
&gt;&gt; type inference algorithm gets complicated, and GHC&#39;s is certainly<br>
&gt;&gt; complicated.<br>
&gt;&gt;<br>
&gt;&gt; Here&#39;s an example:<br>
&gt;&gt;<br>
&gt;&gt;   type family F a b<br>
&gt;&gt;   data instance F Int [a] = Mk { f :: Int }<br>
&gt;&gt;<br>
&gt;&gt;   g :: F Int b  -&gt; ()<br>
&gt;&gt;   h :: F a [Bool] -&gt; ()<br>
&gt;&gt;<br>
&gt;&gt;   k x = (g x, x.f, h x)<br>
&gt;&gt;<br>
&gt;&gt; Consider type inference on k.  Initially we know nothing about the<br>
&gt;&gt; type of x.<br>
&gt;&gt; * From the application (g x) we learn that x&#39;s type has<br>
&gt;&gt;   shape (F Int &lt;something&gt;).<br>
&gt;&gt; * From the application (h x) we learn that x&#39;s type has<br>
&gt;&gt;   shape (F &lt;something else&gt; [Bool])<br>
&gt;&gt; * Hence x&#39;s type must be (F Int [Bool])<br>
&gt;&gt; * And hence, using the data family we can see which field<br>
&gt;&gt;   f is intended.<br>
&gt;&gt;<br>
&gt;&gt; Notice that<br>
&gt;&gt; a) Neither left to right nor right to left would suffice<br>
&gt;&gt; b) There is significant interaction with type/data families<br>
&gt;&gt;    (and I can give you more examples with classes and GADTs)<br>
&gt;&gt; c) In passing we note that it is totally unclear how (Plan A)<br>
&gt;&gt;    would deal with data families<br>
&gt;&gt;<br>
&gt;&gt; This looks like a swamp.  In a simple Hindley-Milner typed language<br>
&gt;&gt; you might get away with some informal heuristics, but Haskell is far<br>
&gt;&gt; too complicated.<br>
&gt;&gt;<br>
&gt;&gt; Fortunately we know exactly what to do; it is described in some detail<br>
&gt;&gt; in our paper &quot;Modular type inference with local assumptions&quot;<br>
&gt;&gt; <a href="http://www.haskell.org/haskellwiki/Simonpj/Talk:OutsideIn" target="_blank">http://www.haskell.org/haskellwiki/Simonpj/Talk:OutsideIn</a><br>
&gt;&gt;<br>
&gt;&gt; The trick is to *defer* all these decisions by generating *type constraints*<br>
&gt;&gt; and solving them later.  We express it like this:<br>
&gt;&gt;<br>
&gt;&gt;   G, r:t1  |-  r.f : t2,  (Has t1 &quot;f&quot; t2)<br>
&gt;&gt;<br>
&gt;&gt; This says that if r is in scope with type t1, then (r.f) has type t2,<br>
&gt;&gt; plus the constraint (Has t1 &quot;f&quot; t2), which we read as saying<br>
&gt;&gt;<br>
&gt;&gt;   Type t1 must have a field &quot;f&quot; of type t2<br>
&gt;&gt;<br>
&gt;&gt; We gather up all the constraints and solve them.  In solving them<br>
&gt;&gt; we may figure out t1 from some *other* constraint (to the left or<br>
&gt;&gt; right, it&#39;s immaterial. That allow us to solve *this* constraint.<br>
&gt;&gt;<br>
&gt;&gt; So it&#39;s all quite simple, uniform, and beautiful.  It&#39;ll fit right<br>
&gt;&gt; into GHC&#39;s type-constraint solver.<br>
&gt;&gt;<br>
&gt;&gt; But note what has happened: we have simply re-invented SORF.  So the<br>
&gt;&gt; conclusion is this:<br>
&gt;&gt;<br>
&gt;&gt;   the only sensible way to implement FDR is using SORF.<br>
&gt;&gt;<br>
&gt;&gt; What about overloading?<br>
&gt;&gt; ~~~~~~~~~~~~~~~~~~~~~~~<br>
&gt;&gt; A feature of SORF is that you can write functions like this<br>
&gt;&gt;<br>
&gt;&gt;   k :: Has r &quot;f&quot; Int =&gt; r -&gt; Int<br>
&gt;&gt;   k r = r.f + 1<br>
&gt;&gt;<br>
&gt;&gt; Function &#39;k&#39; works on any record that has a field &#39;f&#39;.  This may be<br>
&gt;&gt; cool, but it wasn&#39;t part of our original goal.  And indeed neither FDR<br>
&gt;&gt; nor TDNR offer it.<br>
&gt;&gt;<br>
&gt;&gt; But, the Has constraints MUST exist, in full glory, in the constraint<br>
&gt;&gt; solver.  The only question is whether you can *abstract* over them.<br>
&gt;&gt; Imagine having a Num class that you could not abstract over. So you<br>
&gt;&gt; could write<br>
&gt;&gt;<br>
&gt;&gt;   k1 x = x + x :: Float<br>
&gt;&gt;   k2 x = x + x :: Integer<br>
&gt;&gt;   k3 x = x + x :: Int<br>
&gt;&gt;<br>
&gt;&gt; using the same &#39;+&#39; every time, which generates a Num constraint. The<br>
&gt;&gt; type signature fixes the type to Float, Integer, Int respectively, and<br>
&gt;&gt; tells you which &#39;+&#39; to use.  And that is exactly what ML does!<br>
&gt;&gt;<br>
&gt;&gt; But Haskell doesn&#39;t.  The Coolest Thing about Haskell is that you get<br>
&gt;&gt; to *abstract* over those Num constraints, so you can write<br>
&gt;&gt;<br>
&gt;&gt;  k :: Num a =&gt; a -&gt; a<br>
&gt;&gt;  k x = x + x<br>
&gt;&gt;<br>
&gt;&gt; and now it works over *any* Num type.<br>
&gt;&gt;<br>
&gt;&gt; On reflection, it would be absurd not to do ths same thing for Has<br>
&gt;&gt; constraints.  If we are forced to have Has constraints internally, it<br>
&gt;&gt; woudl be criminal not to abstract over them.  And that is precisely<br>
&gt;&gt; what SORF is.<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; Is (Plan A) worth it?<br>
&gt;&gt; ~~~~~~~~~~~~~~~~<br>
&gt;&gt;<br>
&gt;&gt; Once you have (Plan B), and SORF in full glory, plus of course the<br>
&gt;&gt; existing ability to name fields T_f, S_f, if you want, I think it is<br>
&gt;&gt; highly questionable whether we need the additional complexities of<br>
&gt;&gt; (Plan A)?<br>
&gt;&gt;<br>
&gt;&gt; And I do think (Plan A) has lots of additional complexities that we<br>
&gt;&gt; have not begun to explore yet.  The data-family thing above is an<br>
&gt;&gt; example, and I can think of some others.<br>
&gt;&gt;<br>
&gt;&gt; But even if it was simple, we still have to ask: does *any* additional<br>
&gt;&gt; complexity give enough payoff, if you already have SORF?  I suspect<br>
&gt;&gt; not.<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; Extensions to SORF<br>
&gt;&gt; ~~~~~~~~~~~~~~~~~~<br>
&gt;&gt; Frege lets you add &quot;virtual fields&quot; to a record type, using an extra<br>
&gt;&gt; RExtension mechanism that I do not yet understand.  But SORF lets you<br>
&gt;&gt; do so with no additional mechanism.  See &quot;Virtual record selectors&quot;<br>
&gt;&gt; on <a href="http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields" target="_blank">http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields</a><br>
&gt;&gt; The point is that the existing type-class instance mechanisms do just<br>
&gt;&gt; what we want.<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; Syntax<br>
&gt;&gt; ~~~~~~<br>
&gt;&gt; The debate on the mailing list has moved sharply towards discussing<br>
&gt;&gt; lexical syntax.  I&#39;m not going to engage in that discussion because<br>
&gt;&gt; while it is useful to air opinions, it&#39;s very hard to get agreement.<br>
&gt;&gt; But for the record:<br>
&gt;&gt;<br>
&gt;&gt;  * I don&#39;t mind having Unicode alternatives, but there must be<br>
&gt;&gt;    ASCII syntax too<br>
&gt;&gt;<br>
&gt;&gt;  * I think we must use ordinary dot for field selection.<br>
&gt;&gt;<br>
&gt;&gt;  * I think it&#39;s fine to insist on no spaces; we are already<br>
&gt;&gt;    doing this for qualified names, as someone pointed out<br>
&gt;&gt;<br>
&gt;&gt;  * I think we should not introduce new syntax unless we are<br>
&gt;&gt;    absolutely forced into it.  Haskell&#39;s record update syntax<br>
&gt;&gt;    isn&#39;t great, but we have it.<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; Conclusion<br>
&gt;&gt; ~~~~~~~~~~<br>
&gt;&gt; I am driven to the conclusion that SORF is the way to go.<br>
&gt;&gt; - Every other proposal on the table requires SORF (either<br>
&gt;&gt;   visibly or invisibly)<br>
&gt;&gt; - When you have SORF, you don&#39;t really need anything else<br>
&gt;&gt;<br>
&gt;&gt; The blocking issues are described on<br>
&gt;&gt;  <a href="http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields" target="_blank">http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields</a><br>
&gt;&gt;<br>
&gt;&gt;  a) &quot;Representation hiding&quot; (look for that heading)<br>
&gt;&gt;<br>
&gt;&gt;  b) &quot;Record update&quot; (ditto), most especially for records whose<br>
&gt;&gt;     fields have polymorphic types<br>
&gt;<br>
&gt; I posted to the wiki a possible solution to (b):<br>
&gt; <a href="http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields#AlternativeProposal" target="_blank">http://hackage.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields#AlternativeProposal</a><br>


&gt;<br>
&gt;&gt; If we fix these we can move forward.<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; _______________________________________________<br>
&gt;&gt; Glasgow-haskell-users mailing list<br>
&gt;&gt; <a href="mailto:Glasgow-haskell-users@haskell.org">Glasgow-haskell-users@haskell.org</a><br>
&gt;&gt; <a href="http://www.haskell.org/mailman/listinfo/glasgow-haskell-users" target="_blank">http://www.haskell.org/mailman/listinfo/glasgow-haskell-users</a><br>
&gt;&gt;<br>
&gt;<br>
&gt; _______________________________________________<br>
&gt; Glasgow-haskell-users mailing list<br>
&gt; <a href="mailto:Glasgow-haskell-users@haskell.org">Glasgow-haskell-users@haskell.org</a><br>
&gt; <a href="http://www.haskell.org/mailman/listinfo/glasgow-haskell-users" target="_blank">http://www.haskell.org/mailman/listinfo/glasgow-haskell-users</a><br>
<br>
<br>
_______________________________________________<br>
Glasgow-haskell-users mailing list<br>
<a href="mailto:Glasgow-haskell-users@haskell.org">Glasgow-haskell-users@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/glasgow-haskell-users" target="_blank">http://www.haskell.org/mailman/listinfo/glasgow-haskell-users</a><br>
</blockquote></div><br>