
At 2002-01-18 00:06, Cagdas Ozgenc wrote:
Why does Haskell let you write functions that are not a part of type class?
Well, what classes should such functions as const, id and (.) be members of? const :: a -> b -> a; const x y = x; id :: a -> a; id x = x; (.) :: (b -> c) -> (a -> b) -> (a -> c); (.) f g x = f (g x);
For example instead of
elem :: Eq a => a -> [a] -> Bool map :: (a -> b) -> [a] -> [b]
class Container a where elem :: Eq b => b -> a b -> Bool map :: (b -> c) -> a b -> a c
would define methods that can work on all containers,
Actually this would only work on container type-constructors. If you had a type that was some kind of container only of Char, you could not make it an instance of your Container.
and create a discipline to write more reusable and generic functions.
There's already a generalised version of map, called fmap, that works on any Functor type. Picking the correct generalisation is often not obvious... -- Ashley Yakeley, Seattle WA

Well, what classes should such functions as const, id and (.) be members of?
const :: a -> b -> a; const x y = x;
id :: a -> a; id x = x;
(.) :: (b -> c) -> (a -> b) -> (a -> c); (.) f g x = f (g x);
Well can you give examples of some useful functions? I can live without id, and (.)
For example instead of
elem :: Eq a => a -> [a] -> Bool map :: (a -> b) -> [a] -> [b]
class Container a where elem :: Eq b => b -> a b -> Bool map :: (b -> c) -> a b -> a c
would define methods that can work on all containers,
Actually this would only work on container type-constructors. If you had a type that was some kind of container only of Char, you could not make it an instance of your Container.
Same story, you shouldn't have had a Container of Char only in the first place. For example string class in STL is parametrized based on its character type, ascii, unicode etc. If you really have to have one that works on non-parametrized containers, add another map function in the type-class. Besides the original "map" cannot handle Containers of only Char besides the List. Your argument seems self refuting.

I was tempted to answer your original question with "Because Haskell is not an object oriented language and type classes are not object classes", but I thought that would be churlish. Now you write:
Well can you give examples of some useful functions? I can live without id, and (.)
and I /have/ to say that if you can live without these you aren't writing functional programmes. Jón -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk 31 Chalmers Road jf@cl.cam.ac.uk Cambridge CB1 3SZ +44 1223 570179 (after 14:00 only, please!)

On Fri, Jan 18, 2002 at 12:27:09AM -0800, Ashley Yakeley wrote:
Well, what classes should such functions as const, id and (.) be members of?
const :: a -> b -> a; const x y = x;
id :: a -> a; id x = x;
(.) :: (b -> c) -> (a -> b) -> (a -> c); (.) f g x = f (g x);
Arrows, of course. :) In fact, this is directly from my personal, somewhat tweaked arrow library: class Arrow z where arr :: (a -> b) -> z a b -- at least two of >>>, >>>= and first must must be defined -- (preferably >>> and first, or things get slow...) (>>>) :: z a b -> z b c -> z a c a >>> b = a >>>= first b >>>= arr (\((a,_),_) -> a) (>>>=) :: z a b -> z (b,a) c -> z a c a >>>= b = save a >>> b first :: z a b -> z (a, c) (b, c) first a = (fst >>> a) >>>= arr (\(b,(a,c)) -> (b,c)) id :: z a a id = arr (P.id) const :: a -> z q a const a = arr (P.const a) The idea is that arrows that id-arrows and const-arrows can be given specialized implementations. For instance, we can have a direct term implementation for the arrows: data Term z a b = Arr (a -> b) | Lift (z a b) | forall q . Term z a q :>>> Term z q b | forall q r s . First (Term z a (q,s)) (Term z q r) (Term z (r,s) b) | Id (Term z a b) | Label String (Term z a b) | Const b | Null -- unsafe instance Arrow z => Arrow (Term z) where arr f = Arr f a >>> b = a :>>> b first a = First Null a Null const = Const id = Id Null And then one can optimize them right inside the Haskell program: reduce :: Arrow z => Term z a b -> Term z a b reduce (Const a :>>> Arr b) = reduce (Const (b a)) reduce (Arr a :>>> Const b) = reduce (Const b) reduce (Arr a :>>> Arr b) = reduce (Arr (b . a)) -- ... And after optimization run it again as a real arrow: runTerm :: Arrow z => Term z a b -> z a b runTerm (Arr f) = arr f runTerm (Lift z) = z runTerm (a :>>> b) = runTerm a >>> runTerm b -- ... I never actually pursued this idea to the end, though, so I don't know if this would be useful in practice. But still, it's a neat idea, and gives a reason why const should be in a class. :) Lauri Alanko la@iki.fi
participants (5)
-
Ashley Yakeley
-
Cagdas Ozgenc
-
Jon Fairbairn
-
Lauri Alanko
-
안기영