[Haskell-cafe] Over general types are too easy to make.

timothyhobbs at seznam.cz timothyhobbs at seznam.cz
Sun Sep 2 12:35:16 CEST 2012

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 at Foo -> processFoo foo

   bar at Bar -> processBar bar

   frog at 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.


---------- Původní zpráva ----------
Od: Tim Docker <tim at 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 at 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?


Haskell-Cafe mailing list
Haskell-Cafe at haskell.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20120902/a0bd1075/attachment.htm>

More information about the Haskell-Cafe mailing list