
On Friday 27 July 2007, Jon Fairbairn wrote:
ChrisK
writes: Jon Fairbairn wrote:
I currently only get f :: [t] -> something, so if I later discover that I need to change the input representation to be more efficient than lists, I have to rewrite f. Wouldn't it be so much nicer if I could simply add a declaration
f:: Stream s => s t -> something
and get a function that works on anything in the Stream class? The core of the idea would be to allow classes to include constructors (and associated destructors) so the definition of Stream would include something for ":" and "[]" and their inverses, though I've no real idea of the details; can anyone come up with a plan?
I had been avoiding adding my two cents, but I must object to this.
Because this is starting to sound like one of the maddening things about C++.
Namely, the automatic implicit casting conversions of classes via their single argument constructors.
Unfortunately I'm not sufficiently familiar with C++ to know what this means. Perhaps you could clarify?
Somebody noticed that, in C, you could mix integers and floats (almost) freely, and in Classic C, you could mix pointers and integers freely, and thought this was /such/ a wonderful idea that C++ has special syntax to declare the conversion functions allowing you to, say, mix pointers and pointer-like classes freely, or to mix char*s and strings freely, etc. It's what makes template<alpha> class AutoPtr<alpha>{ alpha *ptr; public: explicit AutoPtr(){ ptr = new alpha; } AutoPtr(alpha *p){ ptr = p; } ~AutoPtr(){ delete ptr; } alpha &operator *(){ return *ptr; } operator (alpha*)(){ return ptr; }}; template<alpha> external void swap(alpha *, alpha *); ... AutoPtr<int> ptr1; AutoPtr<int> ptr2; ... swap (ptr1, ptr2); Type-check.
Despite the obvious interpretation of my message (ahem), I'm not advocating much that's automatic. In the case of lists I was imagining that they would be the default for Streams in much the same way that Integer is the default for Num. I'd be happy to discard that part of the idea (though I'd expect howls of protest from those who want lists to be ruling class citizens).
What if the 'f' in the quoted message above is itself part of a type class. Then one has to decide which instance 'f' is being called and what constructors/destructors are being called to view the 's t' parameter as the correct concrete type. That way lies madness.
Again, I think the difficulty here is a discrepancy between the interpretation of what I wrote and what I intended to mean :-), viz that classes could (in addition to their usual functions) define constructor/deconstructor pairs that would be used in desugaring pattern matching. I didn't mean that constructors of the same name could appear both in classes and in data declarations. So if one had something like
class Stream s where Cons:: a -> s a -> s a Nil:: s a Snoc:: s a -> a -> s a ...
{- an instance definition for Stream would have to somehow give both construction and deconstruction functions for Cons and Nil -}
then a definition of the form
f Nil = ... f (Cons h t) = ...
would be unambiguously f:: Stream s => s a -> ... (in the absence of defaulting). There are issues about checking coverage of cases, but I don't think that's the problem you were raising?
-- Jonathan Cast http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs