SICP section 2.4 set off my wheel-reinvention alarms in a big way. It discusses writing code to use complex numbers in a representation-agnostic way; your complex numbers can be either in polar (r, θ) form or rectangular (x + i y) form, and ideally you'd like not to care. Their solution? "Tag" each number with its representation, by passing around pairs whose first element is a symbol: either 'rectangular or 'polar. Your procedures to (say) find the magnitude of your complex numbers first check the symbol and then (in a nice, generic, data-driven, extensible way) dispatch the correct procedure given the representation you're using.
Which is all very well, but isn't this... y'know... a type system? Given that Scheme obviously has some sort of type system in place so it can complain when I try to add 1 to "fred", aren't we reinventing a pretty large wheel? Is this, in fact, final and clinching proof of Smith's (First) Law?
Well, yes and no. Yes, we are implementing a simple type system, but given that the main thrust of the book is how to write interpreters and compilers, that's a pretty useful thing to know. It's also interesting to see how you can whip up your own type system (and module system) atop pairs and lambdas. It's a very simple type system, but it's not too hard to see how, with a slightly more complicated data structure storing your dispatch tables and possibly some macros to take away the busywork, you could implement inheritance, generics... even something like Frink's physical units tracking. And you could mix and match such systems throughout your program. I can't decide if that would be really really cool, or a maintenance and reuse nightmare :-)
Which is all very well, but isn't this... y'know... a type system? Given that Scheme obviously has some sort of type system in place so it can complain when I try to add 1 to "fred", aren't we reinventing a pretty large wheel? Is this, in fact, final and clinching proof of Smith's (First) Law?
Well, yes and no. Yes, we are implementing a simple type system, but given that the main thrust of the book is how to write interpreters and compilers, that's a pretty useful thing to know. It's also interesting to see how you can whip up your own type system (and module system) atop pairs and lambdas. It's a very simple type system, but it's not too hard to see how, with a slightly more complicated data structure storing your dispatch tables and possibly some macros to take away the busywork, you could implement inheritance, generics... even something like Frink's physical units tracking. And you could mix and match such systems throughout your program. I can't decide if that would be really really cool, or a maintenance and reuse nightmare :-)
Tags:
not to be a jerk, but...
Smith's first law, indeed.
Re: not to be a jerk, but...
Actually, one of the things that annoys me about Haskell, or more precisely about the community, is the way they'll say "It's a standard-defined language, with @benefits!", and in the next breath say "Oh, for that you'll need this new feature in today's VC snapshot of GHC! Isn't it neat?" Now, I have nothing against implementation-defined languages: some of my favourite languages are implementation-defined, in fact. Nor do I have anything against spec-defined languages, provided it's a good spec (and not, say one written by the W3C (http://www.w3.org/TR/xpath20/)). But at least be honest with yourselves, guys! :-)
[I've been thinking of blogging about this and related matters for a while - stay tuned...]
Re: not to be a jerk, but...
class Num r => Cpx c r | c -> r where ...By the way, "multiparameter typeclasses with functional dependencies" is probably the worst name for a language feature I've ever heard. Associated types are just a more natural way of expressing what we are trying to do here: specify that each complex type has an associated "component" type which it can be constructed and destructed from.
I freely admit to being a performance whore; I work on games, it kind of comes with the territory. One huge advantage of Haskell's static type system is "type erasure"; the types tend to go away at compile time and you get static function dispatch. This is also true of C and most of C++ aside from virtual function calls. On the other hand, in the SICP implementation of Complex you end up with all these type tags at runtime which are used for dynamic dispatch. Feel free to correct me if I misunderstood that part of the implementation.
Re: not to be a jerk, but...