
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
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)"