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: case largeMultiConstructorTypedValue of Foo{blah=blah,brg=brg} -> .... Some large block... Bar{lolz=lolz,foofoo=foofoo} -> ...Another large block... Frog{legs=legs,heads=heads} -> Yet another large block... Where the obvious re-factor is: case largeMultiConstructorTypedValue of foo@Foo -> processFoo foo bar@Bar -> processBar bar frog@Frog -> processFrog frog processFoo :: Foo -> SomeType processBar :: Bar -> SomeType processFrog:: Frog -> SomeType 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. It seems to be a probability approaching law, that I run into this for a given multi-constructor type. Regardless of it's purpose. Timothy ---------- Původní zpráva ---------- Od: Tim Docker <tim@dockerz.net> Datum: 2. 9. 2012 Předmět: Re: [Haskell-cafe] Over general types are too easy to make. "On 01/09/12 04:00, timothyhobbs@seznam.cz wrote:
I'd have to say that there is one(and only one) issue in Haskell that bugs me to the point where I start to think it's a design flaw:
It's much easier to type things over generally than it is to type things correctly.
Say we have a
data BadFoo = BadBar{ badFoo::Int} | BadFrog{ badFrog::String, badChicken::Int}
This is fine, until we want to write a function that acts on Frogs but not on Bars. The best we can do is throw a runtime error when passed a Bar and not a Foo:
deBadFrog :: BadFoo -> String deBadFrog (BadFrog s _) = s deBadFrog BadBar{} = error "Error: This is not a frog."
We cannot type our function such that it only takes Frogs and not Bars. This makes what should be a trivial compile time error into a nasty runtime one :(
The only solution I have found to this is a rather ugly one:
data Foo = Bar BarT | Frog FrogT
If I then create new types for each data constructor.
data FrogT = FrogT{ frog::String, chicken::Int}
data BarT = BarT{ foo :: Int}
Then I can type deFrog correctly.
deFrog :: FrogT -> String deFrog (FrogT s _) = s
I'm curious as to what you find ugly about this. It appears you need to distinguish between Bars and Frogs, so making them separate types (and having a 3rd type representing the union) is a natural haskell solution: data Bar = .. data Frog = .. fn1 :: Bar -> .. fn2 :: Frog -> .. fn3 :: Either Bar Frog -> .. Perhaps a more concrete example would better illustrate your problem? Tim _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe (http://www.haskell.org/mailman/listinfo/haskell-cafe)"