<html><body>The thing is, that one ALWAYS wants to create a union of types, and not merely an ad-hock list of data declarations.&nbsp; So why does it take more code to do "the right thing(tm)" than to do "the wrong thing(r)"?&nbsp; Lets take an example from Conor McBride's "she"&nbsp; https://github.com/timthelion/her-lexer/blob/master/src/Language/Haskell/Her/HaLay.lhs#L139&nbsp; Line 139 we have a case statement:<br><br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((i, t) : its') -&gt; case (m, t) of<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Lay _ j, _) | not (null acc) &amp;&amp; i &lt;= j -&gt; (reverse acc, its)<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Lay _ _, Semi) -&gt; (reverse acc, its)<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Lay k _, KW e) | elem (k, e) layDKillaz -&gt; (reverse acc, its)<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Lay _ _, Clo _) -&gt; (reverse acc, its)<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Bra b, Clo b') | b == b' -&gt; (reverse acss, its')<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (m, Ope b) -&gt; case getChunks (Bra b) [] its' of<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (cs, its) -&gt; getChunks m (B b cs : acss) its<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (m, KW e) | elem e lakeys -&gt; case getLines (Seek m e) [] its' of<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (css, its) -&gt; getChunks m ((L e css) : acss) its<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _ -&gt; getChunks m (t : acss) its'<br><br>Maybe we would want to re-factor this like so:<br><br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((i, t) : its') -&gt; case (m, t) of<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; layTup@(Lay{}, _) | layTest layTup -&gt; (reverse acc, its)<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Bra b, Clo b') | b == b' -&gt; (reverse acss, its')<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (m, Ope b) -&gt; case getChunks (Bra b) [] its' of<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (cs, its) -&gt; getChunks m (B b cs : acss) its<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (m, KW e) | elem e lakeys -&gt; case getLines (Seek m e) [] its' of<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (css, its) -&gt; getChunks m ((L e css) : acss) its<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _ -&gt; getChunks m (t : acss) its'<br><br>&gt;&nbsp;&nbsp;&nbsp; where<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp; layTest :: (ChunkMode,Tok) -&gt; Bool<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp; layTest (Lay _ j, _) | not (null acc) &amp;&amp; i &lt;= j = True<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp; layTest (Lay _ _, Semi) = True<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp; layTest (Lay k _, KW e) | elem (k, e) layDKillaz = True<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp; layTest (Lay _ _, Clo _) = True<br>&gt;&nbsp;&nbsp;&nbsp;&nbsp; layTest _ = False<br><br>You see what's wrong with layTest's type?&nbsp; It shouldn't be taking a (ChunkMode,Tok) but rather a (Lay,Tok).&nbsp; You ALWAYS run into this.&nbsp; Perhaps you would understand the problem better, if I hadn't said that the data union of types is too ugly, but that the normal data is too pretty?&nbsp; Everyone ends up getting caught in this trap.&nbsp; And the only way out is to re-write your code with better typing.<br><br>Timothy<br><br><p>Od: Tim Docker &lt;tim@dockerz.net&gt;<br>Datum: 2. 9. 2012<br>Předmět: Re: [Haskell-cafe] Over general types are too easy to make.</p>---------- Původní zpráva ----------<br><blockquote>On 01/09/12 04:00, timothyhobbs@seznam.cz wrote:<br>&gt; I'd have to say that there is one(and only one) issue in Haskell that <br>&gt; bugs me to the point where I start to think it's a design flaw:<br>&gt;<br>&gt; It's much easier to type things over generally than it is to type <br>&gt; things correctly.<br>&gt;<br>&gt; Say we have a<br>&gt;<br>&gt; &gt;data BadFoo =<br>&gt; &gt; BadBar{<br>&gt; &gt;  badFoo::Int} |<br>&gt; &gt; BadFrog{<br>&gt; &gt;  badFrog::String,<br>&gt; &gt;  badChicken::Int}<br>&gt;<br>&gt; This is fine, until we want to write a function that acts on Frogs but <br>&gt; not on Bars.  The best we can do is throw a runtime error when passed <br>&gt; a Bar and not a Foo:<br>&gt;<br>&gt; &gt;deBadFrog :: BadFoo -&gt; String<br>&gt; &gt;deBadFrog (BadFrog s _) = s<br>&gt; &gt;deBadFrog BadBar{}      = error "Error: This is not a frog."<br>&gt;<br>&gt; We cannot type our function such that it only takes Frogs and not <br>&gt; Bars.  This makes what should be a trivial compile time error into a <br>&gt; nasty runtime one :(<br>&gt;<br>&gt; The only solution I have found to this is a rather ugly one:<br>&gt;<br>&gt; &gt;data Foo = Bar BarT | Frog FrogT<br>&gt;<br>&gt; If I then create new types for each data constructor.<br>&gt;<br>&gt; &gt;data FrogT = FrogT{<br>&gt; &gt; frog::String,<br>&gt; &gt; chicken::Int}<br>&gt;<br>&gt; &gt;data BarT = BarT{<br>&gt; &gt; foo :: Int}<br>&gt;<br>&gt; Then I can type deFrog correctly.<br>&gt;<br>&gt; &gt;deFrog :: FrogT -&gt; String<br>&gt; &gt;deFrog (FrogT s _) = s<br>&gt;<br><br>I'm curious as to what you find ugly about this. It appears you need to <br>distinguish between Bars and Frogs, so making them separate types (and <br>having a 3rd type representing the union) is a natural haskell solution:<br><br>   data Bar = ..<br>   data Frog = ..<br><br>   fn1 :: Bar -&gt; ..<br>   fn2 :: Frog -&gt; ..<br>   fn3 :: Either Bar Frog -&gt; ..<br><br>Perhaps a more concrete example would better illustrate your problem?<br><br>Tim<br><br><br><br><br><br>_______________________________________________<br>Haskell-Cafe mailing list<br>Haskell-Cafe@haskell.org<br><a href="http://www.haskell.org/mailman/listinfo/haskell-cafe">http://www.haskell.org/mailman/listinfo/haskell-cafe</a></blockquote></body></html>