
"Cagdas Ozgenc"
Greetings.
Why does Haskell let you write functions that are not a part of type class? For example instead of
the goal of type class is to allow overloading of function, so for example id x = x is not subject to overloading => no use to put it in a type class.
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, and create a discipline to write more reusable and generic functions.
yes, that's right that map and elem could be put in a type class, but that's hard and require more advanced feature of haskell (here you use constructor class but you need more : multi-parameter class, ....) see http://www.cse.ogi.edu/~mpj/fds.html.
Thanks
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Yoann Padioleau, INSA de Rennes, France, Opinions expressed here are only mine. Je n'écris qu'à titre personnel. **____ Get Free. Be Smart. Simply use Linux and Free Software. ____**

the goal of type class is to allow overloading of function, so for example id x = x is not subject to overloading => no use to put it in a type
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, and create a discipline to write more reusable and generic functions.
yes, that's right that map and elem could be put in a type class, but
class. Because it doesn't do anything? that's hard and require
more advanced feature of haskell (here you use constructor class but you need more : multi-parameter class, ....) see http://www.cse.ogi.edu/~mpj/fds.html.
You shouldn't be using multi paramater type classes in place of type constructors. Then you will have the ambiguity problems that you mention on you web site. Multi parameter type classes have the benefit of using multi dispatch based on two non related types.

On Fri, 18 Jan 2002, Cagdas Ozgenc wrote:
the goal of type class is to allow overloading of function, so for example id x = x is not subject to overloading => no use to put it in a type class.
Because it doesn't do anything?
I believe that (assuming of course that you aren't a simplicity fanatic who programs only using the S, K, I combinators [1]) id is useful for interfacing with very general functions which have an a->a argument which isn't necessary for what you're doing, e.g., altSumsTransformedList :: (a->a) -> a-> [a] -> a altSumsTransfromedList f e (x:xs) = f x - altSumsTransfromedList f e xs then you can get the simple alternating sum of the original list simply by using altSumsTransfromedList id A much more commonly used example is flip f x y = f y x which doesn't seem to do much, but is actually very useful for things use in things like foldr when you've already got a function which does almost what you want but expects its arguments in the opposite order to the one that foldr gives them in. These small functions are very useful, and several of them have counterparts in the C++ STL binders. [1] this is a bad joke reference to the fact that `all functional programs (under an appropriate encoding of the data) can be converted to an equivalent form using just three elementary combinators, S (aka succ), K (aka const) and I (aka id)'. ___cheers,_dave_________________________________________________________ www.cs.bris.ac.uk/~tweed/|`...heat generated by its microprocessors will email:tweed@cs.bris.ac.uk|slope upward exponentially, reaching the power work tel:(0117) 954-5250 |density of a nuclear reactor before 2010'-Intel

Thanks. I am quite convinced actually (no sarchasm involved).
On Fri, 18 Jan 2002, Cagdas Ozgenc wrote:
the goal of type class is to allow overloading of function, so for example id x = x is not subject to overloading => no use to put it in a type class.
Because it doesn't do anything?
I believe that (assuming of course that you aren't a simplicity fanatic who programs only using the S, K, I combinators [1]) id is useful for interfacing with very general functions which have an a->a argument which isn't necessary for what you're doing, e.g.,
altSumsTransformedList :: (a->a) -> a-> [a] -> a altSumsTransfromedList f e (x:xs) = f x - altSumsTransfromedList f e xs
then you can get the simple alternating sum of the original list simply by using
altSumsTransfromedList id
A much more commonly used example is
flip f x y = f y x
which doesn't seem to do much, but is actually very useful for things use in things like foldr when you've already got a function which does almost what you want but expects its arguments in the opposite order to the one that foldr gives them in. These small functions are very useful, and several of them have counterparts in the C++ STL binders.
[1] this is a bad joke reference to the fact that `all functional programs (under an appropriate encoding of the data) can be converted to an equivalent form using just three elementary combinators, S (aka succ), K (aka const) and I (aka id)'.
___cheers,_dave_________________________________________________________ www.cs.bris.ac.uk/~tweed/|`...heat generated by its microprocessors will email:tweed@cs.bris.ac.uk|slope upward exponentially, reaching the power work tel:(0117) 954-5250 |density of a nuclear reactor before 2010'-Intel

Thanks. I am quite convinced actually (no sarchasm involved).
I'm sorry I didn't follow the discussion. From the last few mails, it seems that the difference between fully polymorphic functions like map, id, filter etc. on one hand and overloaded functions on the other hand is not clear:
the goal of type class is to allow overloading of function, so for example id x = x is not subject to overloading => no use to put it in a type class.
Because it doesn't do anything?
<examples by Dave showing that id is useful>
There are fairly simple rules to decide whether or not a function should be in a type class. Notes: 1. The type of x is NOT needed/used <=> there is NO pattern match on x 2. The type of x is needed/used <=> there is AT LEAST ONE pattern match on x 3. Recursive checks are necessary sometimes. This will become clear in the filter example A. In a type class Rule: Put a function f in a type class if and only if For some argument x: (x ranges over more than one type) and (the function needs the type of x in order to do its work) B. Not in a type class Rule: Do NOT put a function f in a type class if (and only if) For each argument x of f: (f doesn't use the type of x) or (x doesn't range over multiple types (ie has a single type)) If someone has a better definition, I would be glad to hear it. I will explain the rules using a few examples. id :: a -> a id x = x There is just one argument to check: x Property: there is no pattern match on x We conclude that rule B applies The check that rule A doesn't apply is left as an exercise to the reader. filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x:xs) | p x = x : filter p xs | otherwise = filter p xs there are two arguments: the function p and the list p is just passed around and it can take any type satisfying (a -> Bool) like (Int -> Bool), (Char -> Bool) etc. Now note 3 (above) comes up. The list is a difficult case. Does it range over multiple types or doesn't it? filter takes as second argument a list, and only a list. No other structure is allowed. Therefore, it doesn't take a range of types there. It takes a single type. But because it is unpacked using pattern matching, we have to check the properties of its components x and xs. The type of x is not used. The list xs is pattern-matched (implicit in "filter p xs") but again, the list itself is only a single structure. The function map is left as an exercise to the reader. Quite regularly we have to work with datatypes other than lists. For example binary trees with elements in the nodes: data BinTree a = Node a (BinTree a) (BinTree a) | Leaf To convert a (BinTree a) to a (BinTree b) by applying a function f :: a -> b on each element, we need a function very similar to map. Unfortunately, map only accepts lists, so we have to write our own function. Of course the technical behaviour is quite different, but for the programmer the behaviour is very similar. For this situation we have fmap :: (a -> b) -> f a -> f b For the type f (of kind * -> *) we can take [] (note that "x :: [] a" is the same as "x :: [a]") or BinTree or some other collection type. However, not an arbitrary type, since the technical implementation of fmap for [] differs from the one for BinTree. Therefore, we have no uniform implementation working for an arbitrary type f. Note the requirement in A (the function needs the type of x in order to do its work) In this case, we need the type of f to choose the right implementation. Thus, we have to put in in a class: class Functor f where fmap :: (a -> b) -> f a -> f b For Maybe (a collection type with only two choices: no elements or one element) we can write: instance Functor Maybe where fmap f Nothing = Nothing fmap f (Just x) = Just (f x) For lists we have (the usual map) instance Functor [] where fmap f [] = [] fmap f (x:xs) = f x : fmap f xs For BinTree we have instance Functor BinTree where fmap f Leaf = Leaf fmap f (Node x t1 t2) = Node (f x) (fmap f t1) (fmap f t2) If we try "fmap (+3) 5", the compiler will tell us that 5 is and Int, and fmap needs Maybe a, [a] or BinTree a. In the three implementations, you see that the second argument of fmap ranges over three different types, while it needs the type of that argument to perform the map. I hope this clears up a few difficulties. Rijk-Jan

Cagdas Ozgenc wrote:
You shouldn't be using multi paramater type classes in place of type constructors. Then you will have the ambiguity problems that you mention on you web site. Multi parameter type classes have the benefit of using multi dispatch based on two non related types.
Ozgenc's opinion is right. See the code below. This is a proper Haskell 98 script, tested under Hugs version December 2001. No need for multi parameter stuff. \begin{code} class Container a where celem :: Eq b => b -> a b -> Bool cmap :: (Eq b, Eq c) => (b->c) -> a b -> a c data MyList a = MyList [a] deriving Show instance Container MyList where celem x (MyList l) = elem x l cmap f (MyList l) = MyList (map f l) \end{code}

Hi there! A ./configure in the fptools root directory gives me $ ./configure *** The top of your build tree is: /home/Administrator/fucker checking build system type... i686-pc-cygwin checking host system type... i686-pc-cygwin checking target system type... i686-pc-cygwin Canonicalised to: i386-unknown-cygwin32 checking for ghc... /cygdrive/c/ghc/ghc-5.02.2/bin/ghc checking version of ghc... 5.02.2 checking for nhc... no checking for nhc98... no checking for hbc... no checking whether #! works in shell scripts... yes checking for perl... /bin/perl checking if your perl works in shell scripts... yes checking for gcc... gcc checking for C compiler default output... a.exe checking whether the C compiler works... yes checking whether we are cross compiling... no checking for executable suffix... .exe checking for object suffix... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking whether you have an ok gcc... yes checking how to run the C preprocessor... gcc -E checking whether gcc accepts -mwin32... yes checking whether gcc accepts -mno-cygwin... yes checking for ok way to do context diffs... diff -C 1 checking for find... /usr/bin/find checking for bison... bison -y checking for flex... flex checking for a BSD compatible install... /usr/bin/install -c checking for ar... /usr/bin/ar checking whether ln -s works... yes checking for sed... /usr/bin/sed checking for time... no checking for gtar... no checking for tar... /usr/bin/tar checking for gzip... /usr/bin/gzip checking for openjade... no checking for jade... no checking for DocBook CATALOG... no Warning: You will not be able to build the documentation. checking for happy... /cygdrive/c/happy/happy-1.11/bin/happy checking for version of happy... 1.11 checking for ANSI C header files... no checking for Files.h... no checking for arpa/inet.h... no checking for assert.h... no checking for console.h... no checking for ctype.h... no checking for dirent.h... no checking for errno.h... no checking for fcntl.h... no checking for float.h... no checking for ftw.h... no checking for grp.h... no checking for ieee754.h... no checking for inttypes.h... no checking for limits.h... no checking for malloc.h... no checking for memory.h... no checking for nlist.h... no checking for pascal.h... no checking for pwd.h... no checking for sgtty.h... no checking for siginfo.h... no checking for signal.h... no checking for stat.h... no checking for stdint.h... no checking for stdlib.h... no [...] Why doesnt the configure script recognize the header files? Compiling programs using gcc works fine as usual. Does somebody know what's wrong here? Thanks Johannes
participants (6)
-
Cagdas Ozgenc
-
D. Tweed
-
Johannes Goetz
-
Rijk-Jan van Haaften
-
Yoann Padioleau
-
안기영