
Hi all, I've written a small type class that is meant to behave a bit like Show: class Show a => Echo a where echo :: a -> String echoList :: [a] -> String echoListSep :: a -> String echo = show echoListSep _ = " " echoList [] = "" echoList [x] = echo x echoList (x:xs) = echo x ++ echoListSep x ++ echoList xs instance Echo Char where echo c = [c] echoListSep _ = "" instance Echo a => Echo [a] where echo = echoList instance Echo Int where instance Echo Integer where instance Echo Double where instance Echo Float where gen = map (const 1) f xs = map echo $ gen xs However the code doesn't compile on the last line. But it does compile if I replace 'echo' with 'show'. What's missing to make my typeclass behave like Show and accept input of any type (besides all the missing instances...)? I looked at the code for Show but I didn't see anything that looked "magical"... Thanks, Patrick -- ===================== Patrick LeBoutillier Rosemère, Québec, Canada

Patrick, I fixed it by adding a type signature to this line: gen = map (const (1::Int)) The problem is that the literal '1' is of type Num t => t, which is never tied to a concrete type anywhere. It has to know the type definitely before it can decide which type class to use. Steve Patrick LeBoutillier wrote:
Hi all,
I've written a small type class that is meant to behave a bit like Show:
class Show a => Echo a where echo :: a -> String echoList :: [a] -> String echoListSep :: a -> String
echo = show echoListSep _ = " "
echoList [] = "" echoList [x] = echo x echoList (x:xs) = echo x ++ echoListSep x ++ echoList xs
instance Echo Char where echo c = [c] echoListSep _ = ""
instance Echo a => Echo [a] where echo = echoList
instance Echo Int where instance Echo Integer where instance Echo Double where instance Echo Float where
gen = map (const 1)
f xs = map echo $ gen xs
However the code doesn't compile on the last line. But it does compile if I replace 'echo' with 'show'. What's missing to make my typeclass behave like Show and accept input of any type (besides all the missing instances...)? I looked at the code for Show but I didn't see anything that looked "magical"...
Thanks,
Patrick

Am Donnerstag 04 Februar 2010 23:14:33 schrieb Patrick LeBoutillier:
Hi all,
I've written a small type class that is meant to behave a bit like Show:
class Show a => Echo a where echo :: a -> String echoList :: [a] -> String echoListSep :: a -> String
echo = show echoListSep _ = " "
echoList [] = "" echoList [x] = echo x echoList (x:xs) = echo x ++ echoListSep x ++ echoList xs
instance Echo Char where echo c = [c] echoListSep _ = ""
instance Echo a => Echo [a] where echo = echoList
instance Echo Int where instance Echo Integer where instance Echo Double where instance Echo Float where
gen = map (const 1)
f xs = map echo $ gen xs
However the code doesn't compile on the last line. But it does compile if I replace 'echo' with 'show'. What's missing to make my typeclass behave like Show and accept input of any type (besides all the missing instances...)? I looked at the code for Show but I didn't see anything that looked "magical"...
The "magic" is that Show is defined in the standard libraries. Read http://haskell.org/onlinereport/decls.html#sect4.3.4 In particular, the last bullet point of "In situations where an ambiguous type is discovered, an ambiguous type variable, v, is defaultable if: * v appears only in constraints of the form C v, where C is a class, and * at least one of these classes is a numeric class, (that is, Num or a subclass of Num), and * all of these classes are defined in the Prelude or a standard library (Figures 6.2--6.3, pages -- show the numeric classes, and Figure 6.1, page , shows the classes defined in the Prelude.) " Now, gen xs :: Num a => [a] And you want to map echo over it, so we get the constraint (Num a, Echo a). Echo is not defined in the standard libraries, thus no defaulting takes place, you have to specify the type of 1 explicitly, map echo (gen xs :: [Int]) should work. In real programmes, the type is often deducible from the context, so you'll be bitten by the defaulting restrictions less often then than at the ghci prompt. There's a proposal (or a couple) to change the defaulting rules in coming language standards, see e.g. http://hackage.haskell.org/trac/haskell- prime/wiki/Defaulting
Thanks,
Patrick
HTH, Daniel

Daniel,
Thanks a lot for the info! That's a subtlety I wasn't aware of.
Patrick
On Thu, Feb 4, 2010 at 5:37 PM, Daniel Fischer
Am Donnerstag 04 Februar 2010 23:14:33 schrieb Patrick LeBoutillier:
Hi all,
I've written a small type class that is meant to behave a bit like Show:
class Show a => Echo a where echo :: a -> String echoList :: [a] -> String echoListSep :: a -> String
echo = show echoListSep _ = " "
echoList [] = "" echoList [x] = echo x echoList (x:xs) = echo x ++ echoListSep x ++ echoList xs
instance Echo Char where echo c = [c] echoListSep _ = ""
instance Echo a => Echo [a] where echo = echoList
instance Echo Int where instance Echo Integer where instance Echo Double where instance Echo Float where
gen = map (const 1)
f xs = map echo $ gen xs
However the code doesn't compile on the last line. But it does compile if I replace 'echo' with 'show'. What's missing to make my typeclass behave like Show and accept input of any type (besides all the missing instances...)? I looked at the code for Show but I didn't see anything that looked "magical"...
The "magic" is that Show is defined in the standard libraries. Read http://haskell.org/onlinereport/decls.html#sect4.3.4 In particular, the last bullet point of
"In situations where an ambiguous type is discovered, an ambiguous type variable, v, is defaultable if:
* v appears only in constraints of the form C v, where C is a class, and * at least one of these classes is a numeric class, (that is, Num or a subclass of Num), and * all of these classes are defined in the Prelude or a standard library (Figures 6.2--6.3, pages -- show the numeric classes, and Figure 6.1, page , shows the classes defined in the Prelude.) "
Now,
gen xs :: Num a => [a]
And you want to map echo over it, so we get the constraint (Num a, Echo a).
Echo is not defined in the standard libraries, thus no defaulting takes place, you have to specify the type of 1 explicitly,
map echo (gen xs :: [Int])
should work.
In real programmes, the type is often deducible from the context, so you'll be bitten by the defaulting restrictions less often then than at the ghci prompt.
There's a proposal (or a couple) to change the defaulting rules in coming language standards, see e.g. http://hackage.haskell.org/trac/haskell- prime/wiki/Defaulting
Thanks,
Patrick
HTH, Daniel
-- ===================== Patrick LeBoutillier Rosemère, Québec, Canada
participants (3)
-
Daniel Fischer
-
Patrick LeBoutillier
-
Stephen Blackheath [to Haskell-Beginners]