
Happy Holidays, I was wondering if it this small snippet of code could be altered to require fewer OPTIONS -fallow-... switches. It creates a show-what-i-mean function called "swim" that takes a variable number of arguments, and treats strings as-is, calling show on the other arguments.
{-# OPTIONS -fglasgow-exts #-} {-# OPTIONS -fallow-undecidable-instances #-} {-# OPTIONS -fallow-incoherent-instances #-} {-# OPTIONS -fallow-overlapping-instances #-}
-- Want to show strings "as-is"
class (Show a) => MyShow a where myShow :: a -> String myShow = show
instance MyShow String where myShow = id
instance (Show b) => MyShow b
-- Want to take variable number of arguments
class PVShow a r where pvShow :: String -> a -> r
instance (MyShow b) => PVShow b String where pvShow oldString b = oldString ++ (myShow b)
instance (MyShow b,PVShow a r) => PVShow b (a->r) where pvShow oldString b = pvShow (oldString ++ (myShow b))
-- swim is short for Show What I Mean
swim :: (PVShow a r) => a -> r swim = pvShow ""
-- Demonstates of polymorphic and first class nature of swim
test foo = foo " and " 7 " are "
-- Tests
main = do putStrLn $ swim "Hello" " " "World #" [17,18,19] "!" putStrLn $ test (swim "I also think " [4,5,6]) "cool" "."
GHCI session: Main> main Hello World #[17,18,19]! I also think [4,5,6] and 7 are cool. *Main> Could this be improved by TypeEq machinery? Is there a Haskell 98 way to make myShow work this way? -- Chris Kuklewicz

On Tue, Dec 27, 2005 at 04:39:34PM +0000, Chris Kuklewicz wrote:
Happy Holidays,
I was wondering if it this small snippet of code could be altered to require fewer OPTIONS -fallow-... switches.
It creates a show-what-i-mean function called "swim" that takes a variable number of arguments, and treats strings as-is, calling show on the other arguments.
Perhaps you can use the same trick that allows "show" to treat String = [Char] differently than all other lists? I mean the showList method. Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

Tomasz Zielonka wrote:
On Tue, Dec 27, 2005 at 04:39:34PM +0000, Chris Kuklewicz wrote:
Happy Holidays,
I was wondering if it this small snippet of code could be altered to require fewer OPTIONS -fallow-... switches.
It creates a show-what-i-mean function called "swim" that takes a variable number of arguments, and treats strings as-is, calling show on the other arguments.
Perhaps you can use the same trick that allows "show" to treat String = [Char] differently than all other lists? I mean the showList method.
Best regards Tomasz
That is where the class has a default function to perform showList, and the instance Show Char where showList = specialized version. The MyShow class is similar, but does not work without all the extensions. I have class Show a => MyShow a where myShow = show. Then I have a specialized version for instance MyShow String where myShow = id. If I wrap everything in a data contructor I get more flexibility, but I don't yet see how (even with GADT) to simplify things. -- Chris

Hello, On Tue, 27 Dec 2005 16:39:34 +0000, Chris Kuklewicz wrote:
Happy Holidays,
I was wondering if it this small snippet of code could be altered to require fewer OPTIONS -fallow-... switches.
Here is a partial solution using only -fglasgow-exts:
module MyShow where
class MyShow t where swim :: String -> t
instance MyShow String where swim = id
instance (Show a, MyShow t) => MyShow (a -> t) where swim s x = swim (s ++ show x)
test foo = foo " and " 7 " are "
main = do putStrLn $ swim "Hello" " " "World #" [17,18,19] "!" putStrLn $ test (swim "I also think " [4,5,6]) "cool" "."
The problem of this solution is that, because we are using show in the definition of swim for (a -> t), the strings are beeing printed with extra "\"". *MyShow> main Hello" ""World #"[17,18,19]"!" I also think [4,5,6]" and "7" are ""cool""." You can, ofcourse, add a new instance for (String -> t) but that will cost you -fallow-incoherent-instances and -fallow-overlapping-instances.
instance MyShow t => MyShow (String -> t) where swim s x = swim (s ++ x)
Could this be improved by TypeEq machinery? Is there a Haskell 98 way to make myShow work this way?
The problem of the previous solution is that you do not want, in the general case, use the default instance of Show for Strings. An alternative is to just introduce a newtype S (isomorphic to String) that allows you to handle Strings differently:
module MyShow where
class MyShow t where swim :: S -> t
newtype S = S {unS :: String}
instance MyShow S where swim = id
instance Show S where show = unS
instance (Show a, MyShow t) => MyShow (a -> t) where swim s x = swim (S $ unS s ++ show x)
putSLn = putStrLn . unS
test foo = foo (S " and ") 7 (S " are ")
main = do putSLn $ swim (S "Hello") (S " ") (S "World #") [17,18,19] (S "!") putSLn $ test (swim (S "I also think ") [4,5,6]) (S "cool") (S ".")
By using the newtype S instead of Haskell String, you obtain an Haskell 98 solution. I am not sure if this is good enough for you but it seems a good compromise. Hope it helps! Cheers, Bruno

Bruno Oliveira wrote:
On Tue, 27 Dec 2005 16:39:34 +0000, Chris Kuklewicz wrote:
I was wondering if it this small snippet of code could be altered to require fewer OPTIONS -fallow-... switches.
Here is a partial solution using only -fglasgow-exts:
...deleted...
The problem of this solution is that, because we are using show in the definition of swim for (a -> t), the strings are beeing printed with extra "\"".
*MyShow> main Hello" ""World #"[17,18,19]"!" I also think [4,5,6]" and "7" are ""cool""."
The extra double quotes being what I am trying to avoid with MyShow
instance MyShow t => MyShow (String -> t) where swim s x = swim (s ++ x)
This is interesting. It does remove the need for -fallow-undecidable-instances. Thanks.
Could this be improved by TypeEq machinery? Is there a Haskell 98 way to make myShow work this way?
The problem of the previous solution is that you do not want, in the general case, use the default instance of Show for Strings. An alternative is to just introduce a newtype S (isomorphic to String) that allows you to handle Strings differently:
... deleted...
By using the newtype S instead of Haskell String, you obtain an Haskell 98 solution. I am not sure if this is good enough for you but it seems a good compromise.
Hope it helps!
Cheers,
Bruno
I did find the newtype solution, and trying to avoid that is what motivated such ugly switch flipping usage of GHC. My intuition was that this example of creating "something like a sub-type-class of Show" which treats String differently ought to be possible. And it is possible, and I would hazard a guess that your solution with "MyShow (String->t)" is safe in spite of the extra switches. The sad thing is that the two -fallow switches infect client code that uses the MyShow module. So allowing those tricks for class MyShow must turn on for classes in code that imports MyShow. If GHC could -fallow those flags only for certain typeclasses then it would be confinable. In principle, could GHC ever be extended to confine -fallow this way? -- Chris

Chris Kuklewicz wrote:
*MyShow> main Hello" ""World #"[17,18,19]"!" I also think [4,5,6]" and "7" are ""cool""."
The extra double quotes being what I am trying to avoid with MyShow
This is your only special case, a single list of a sigle type that is different from other lists? To avoid undecidable, incoherent and other nasty instances, just do what the Prelude does: class MyShow t where swim :: t -> String swimList :: [t] -> String swimList [] = "[]" swimList xs = '[' : foldr1 (\x -> (swim x ++) . (',' :)) "]" xs instance MyShow Char where swim = (:[]) swimList = id Untested, but you get the idea. It's pure Haskell 98. Heck, it's almost Prelude.Show. It won't scale to more type constructors easily, but you didn't ask for that ability, either ;-) Udo. -- "As far as Clinton supposedly cheating on his wife, what do people think he's going to do? Be president of another country while he's president of ours?" -- Tom R., age 12

Udo Stenzel wrote:
This is your only special case, a single list of a sigle type that is different from other lists? To avoid undecidable, incoherent and other nasty instances, just do what the Prelude does:
class MyShow t where swim :: t -> String swimList :: [t] -> String swimList [] = "[]" swimList xs = '[' : foldr1 (\x -> (swim x ++) . (',' :)) "]" xs
instance MyShow Char where swim = (:[]) swimList = id
Untested, but you get the idea. It's pure Haskell 98. Heck, it's almost Prelude.Show. It won't scale to more type constructors easily, but you didn't ask for that ability, either ;-)
Udo.
You example treats Char specially. I want (swim 'a') to be ("'a'") not ("a"). I want every type but String to eventually use the builtin "show" function. This is not what your example does unless I make it longer. For example, if I wrote instance MyShow Int where swim = show instance MyShow Double where swim = show ... many many instances ... then it would work. I need for the compiler to understand that MyShow String has swim = id and MyShow (any other Show instance but String) has swim = show. GHC can do this, the working examples with -fallow* prove it. I was curious if there is some type level programming knowledge in the Haskell community which would allow me to express (any other Show instance but String) in a non-overlapping way. I can read the HList and OOHaskell work, and see the advanced type level programming, but I am not yet clever enough to derive a solution for MyShow. -- Chris
participants (4)
-
Bruno Oliveira
-
Chris Kuklewicz
-
Tomasz Zielonka
-
Udo Stenzel