
Brian Hurt wrote:
So, style question for people, if I can. I have a certain problem- basically, I have a bunch of functions which need a special function, of type a -> Foo say. And a bunch of other functions which can define that function on some type of interest, and then what to call the first batch of functions. I can do this either by defining a type class, something like: class Fooable a where toFoo :: a -> Foo or I can simply have all the functions which need a toFoo take an extra agrument. Performance really isn't that important here, so it's really a matter of style- which approach would people prefer in this case?
For issues of style, I would say to use type-classes. However, this isn't strictly a question of style. As Luke Palmer mentions there are differences of power between the two. In particular, imagine that you have two different and valid ways to convert the same type into Foo; which do you choose? With the continuation/combinator/argument approach this is a non-issue since you can just pass in the one you need. With type-classes it's tricky since they're the same type, which leads to hacks with newtype wrappers or phantom types. If there is guaranteed to be only one valid transformation from any given type into Foo, then type-classes make your intentions clear and they never run into this issue. If more than one valid transformation could exist for some type, then the extra argument is cleaner. Note that when I say "any given type" I mean the domain of values along with its semantic connotations. For instance, there's a straightforward way of 'converting' Double into an instance of Num. However, if we semantically interpret the values of Double as if they were in the log-domain, then there is a different way to convert it into Num[1]. But really, these are different types because they have different semantics even if they have the "same" values. Though much abused, newtype declarations are intended to capture exactly this distinction between values and semantics, and they make it straightforward for the Haskell type-checker to see that they are indeed different types. [1] http://hackage.haskell.org/cgi-bin/hackage-scripts/package/logfloat -- Live well, ~wren