I have a curious Haskell design pattern. It's called "one class per function". It's strange, but I find that as I need more and more generality, I end up with classes that look like this: class (Monad m) => MonadGettableReference m r where { get :: forall a. r a -> m a; }; class (Monad m) => MonadSettableReference m r where { set :: forall a. r a -> a -> m (); }; ...and then I'll have a bunch of "joining" classes. Here's a joining class: class ( MonadGettableReference m r, MonadSettableReference m r ) => MonadFixedReference m r; instance ( MonadGettableReference m r, MonadSettableReference m r ) => MonadFixedReference m r; Sooner or later, for maximum generality they're all going to look like this: class Foo a where { foo :: a; }; class Bar a where { bar :: a; }; class ( Monad m, forall a. Foo (a -> m a), -- pending appropriate extension forall b. Bar (m b) ) => FooBar m; instance ( Monad m, forall a. Foo (a -> m a), forall b. Bar (m b) ) => FooBar m; I'm not sure if this is a good thing or a bad thing or what. -- Ashley Yakeley, Seattle WA
On Thursday 16 May 2002 11:48 pm, Ashley Yakeley wrote:
I have a curious Haskell design pattern. It's called "one class per function". [...] I'm not sure if this is a good thing or a bad thing or what.
You might want to take a look at the class system for the language Concurrent Clean. It encourages a "one class per function" setup similar to the one you mentioned, but without nearly as much syntax. The following is quoted from http://www.cs.kun.nl/~clean/About_Clean/tutorial/tutorial.html: In Clean a class is a family of functions with the same name.... As a very simple example consider the class of increment functions. class inc t :: t -> t This says that the class inc has type variable t. There is only a single manipulation function in this class, which is also named inc. The type of this increment function is t -> t. Instances of this class for integers and reals are defined by: instance inc Int where inc i = i+1 instance inc Real where inc r = r+1.0 ... - Brian Huffman
G'day all. On Thu, May 16, 2002 at 11:48:58PM -0700, Ashley Yakeley wrote:
I have a curious Haskell design pattern. It's called "one class per function".
When used in conjunction with fundeps, I call it "hacking C++-style function overloading". Sometimes I think it would be handy if the Prelude used it more, because then you could have full overloading for types which don't quite play by the rules of the standard classes. For example: class Mult a b c | a b -> c where (*) :: a -> b -> c class Add a b c | a b -> c where (+) :: a -> b -> c {- etc -} class (Mult a a a, Add a a a, {- etc -}) => Num a where {- etc -} Then you could use the standard notation to multiply matrices with vectors and Haskell wouldn't complain. I'm not sure that this is necessarily something to be encouraged, of course... Cheers, Andrew Bromage
Ashley Yakeley <ashley@semantic.org> writes:
I have a curious Haskell design pattern. It's called "one class per function".
[...]
I'm not sure if this is a good thing or a bad thing or what.
In many cases, I think a finer split would be advantageous, e.g. the much-debated "Num". One obvious disadvantage is that a lot of inferred type classes may become less readable (:t saying "Num a => .." is probably more informative for many than "CommutativeRing a => ..") -kzm -- If I haven't seen further, it is by standing in the footprints of giants
participants (4)
-
Andrew J Bromage -
Ashley Yakeley -
Brian Huffman -
ketil@ii.uib.no