<html><body><p>The problem with the last example I gave is evident in your statement "It appears you need to distinguish between Bars and Frogs". I have written quite a number of largish code bases, and I've run into the following problem every time:</p><p><br></p><p>case largeMultiConstructorTypedValue of</p><p> Foo{blah=blah,brg=brg} -> .... Some large block...</p><p> Bar{lolz=lolz,foofoo=foofoo} -> ...Another large block...</p><p> Frog{legs=legs,heads=heads} -> Yet another large block...</p><p><br></p><p>Where the obvious re-factor is:<br></p><p><br></p><p>case largeMultiConstructorTypedValue of</p><p> foo@Foo -> processFoo foo<br></p><p> bar@Bar -> processBar bar<br></p><p> frog@Frog -> processFrog frog</p><p><br></p><p>processFoo :: Foo -> SomeType</p><p>processBar :: Bar -> SomeType</p><p>processFrog:: Frog -> SomeType</p><p><br></p><p>I always want to be able to make procssFoo, processBar, and processFrog typestrict to their associated constructors. Otherwise they are doomed to be incomplete functions.</p><p><br></p><p>It seems to be a probability approaching law, that I run into
this for a given multi-constructor type. Regardless of it's purpose.</p><p><br></p><p>Timothy</p><p><br></p><p>---------- Původní zpráva ----------<br>Od: Tim Docker <tim@dockerz.net><br>Datum: 2. 9. 2012<br>Předmět: Re: [Haskell-cafe] Over general types are too easy to make.</p><blockquote>On 01/09/12 04:00, timothyhobbs@seznam.cz wrote:<br>> I'd have to say that there is one(and only one) issue in Haskell that <br>> bugs me to the point where I start to think it's a design flaw:<br>><br>> It's much easier to type things over generally than it is to type <br>> things correctly.<br>><br>> Say we have a<br>><br>> >data BadFoo =<br>> > BadBar{<br>> > badFoo::Int} |<br>> > BadFrog{<br>> > badFrog::String,<br>> > badChicken::Int}<br>><br>> This is fine, until we want to write a function that acts on Frogs but <br>> not on Bars. The best we can do is throw a runtime error when passed <br>> a Bar and not a Foo:<br>><br>> >deBadFrog :: BadFoo -> String<br>> >deBadFrog (BadFrog s _) = s<br>> >deBadFrog BadBar{} = error "Error: This is not a frog."<br>><br>> We cannot type our function such that it only takes Frogs and not <br>> Bars. This makes what should be a trivial compile time error into a <br>> nasty runtime one :(<br>><br>> The only solution I have found to this is a rather ugly one:<br>><br>> >data Foo = Bar BarT | Frog FrogT<br>><br>> If I then create new types for each data constructor.<br>><br>> >data FrogT = FrogT{<br>> > frog::String,<br>> > chicken::Int}<br>><br>> >data BarT = BarT{<br>> > foo :: Int}<br>><br>> Then I can type deFrog correctly.<br>><br>> >deFrog :: FrogT -> String<br>> >deFrog (FrogT s _) = s<br>><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 -> ..<br> fn2 :: Frog -> ..<br> fn3 :: Either Bar Frog -> ..<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>