How do I let a function in Haskell depend on the type of its argument? - haskell

I tried to write a variation on show that treats strings differently from other instances of Show, by not including the " and returning the string directly. But I don't know how to do it. Pattern matching? Guards? I couldn't find anything about that in any documentation.
Here is what I tried, which doesn't compile:
show_ :: Show a => a -> String
show_ (x :: String) = x
show_ x = show x

If possible, you should wrap your values of type String up in a newtype as #wowofbob suggests.
However, sometimes this isn't feasible, in which case there are two general approaches to making something recognise String specifically.
The first way, which is the natural Haskell approach, is to use a type class just like Show to get different behaviour for different types. So you might write
class Show_ a where
show_ :: a -> String
and then
instance Show_ String where
show_ x = x
instance Show_ Int where
show_ x = show x
and so on for any other type you want to use. This has the disadvantage that you need to explicitly write out Show_ instances for all the types you want.
#AndrewC shows how you can cut each instance down to a single line, but you'll still have to list them all explicitly. You can in theory work around this, as detailed in this question, but it's not pleasant.
The second option is to get true runtime type information with the Typeable class, which is quite short and simple in this particular situation:
import Data.Typeable
[...]
show_ :: (Typeable a, Show a) => a -> String
show_ x =
case cast x :: Maybe String of
Just s -> s
Nothing -> show x
This is not a natural Haskell-ish approach because it means callers can't tell much about what the function will do from the type.
Type classes in general give constrained polymorphism in the sense that the only variations in behaviour of a particular function must come from the variations in the relevant type class instances. The Show_ class gives some indication what it's about from its name, and it might be documented.
However Typeable is a very general class. You are delegating everything to the specific function you are calling; a function with a Typeable constraint might have completely different implementations for lots of different concrete types.
Finally, a further elaboration on the Typeable solution which gets closer to your original code is to use a couple of extensions:
{-# LANGUAGE ViewPatterns, ScopedTypeVariables #-}
import Data.Typeable
[...]
show_ :: (Typeable a, Show a) => a -> String
show_ (cast -> Just (s :: String)) = s
show_ x = show x
The use of ViewPatterns allows us to write the cast inside a pattern, which may fit in more nicely with more complicated examples. In fact we can omit the :: String type constraint because the body of this cases forces s to be the result type of show_, i.e. String, anyway. But that's a little obscure so I think it's better to be explicit.

You can wrap it into newtype and make custom Show instance for it:
newtype PrettyString = PrettyString { toString :: String }
instance Show PrettyString where
show (PrettyString s) = "$$" ++ s ++ "$$" -- for example
And then use it like below:
main = getLine >>= print . PrettyString

TL;DR:
Copy the prelude's way and use showList_ as a class function to generate instances for lists so you can override the definition for String.
Caveat
For the record, wowofbob's answer using a newtype wrapper is the simple, clean solution I would use in real life, but I felt it was instructive to also look at some of how the Prelude does this.
intercalate commas by default
The way this is done in the prelude is to make the Show class have a function for showing lists, with a default definition that you can override.
import Data.List (intercalate)
I'll use intercalate :: [a] -> [[a]] -> [a] to put commas in between stuff:
ghci> intercalate "_._" ["intercalate","works","like","this"]
"intercalate_._works_._like_._this"
Make a showList_ class function, and default to show and comma-separated lists.
So now the class with the default implementation of the showList function and, importantly, a default show_ implementation that just uses the ordinary show function. To be able to use that, we have to insist that the type is already in the Show typeclass, but that's OK as far as I understand you.
class Show a => Show_ a where
show_ :: a -> String
showList_ :: [a] -> String
show_ = show
showList_ xs = '[' : intercalate ", " (map show_ xs) ++ "]"
The real Show class uses functions of type String -> String instead of String directly for efficiency reasons, and a precedence argument to control the use of brackets, but I'll skip all that for simplicity.
Automatically make instances for lists
Now we can use the showList function to provide an instance for lists:
instance Show_ a => Show_ [a] where
show_ xs = showList_ xs
The Show a => superclass makes instances super-easy
Now we come to some instances. Because of our default show_ implementation, we don't need to do any actual programming unless we want to override the default, which we'll do for Char, because String ~ [Char].
instance Show_ Int
instance Show_ Integer
instance Show_ Double
instance Show_ Char where
show_ c = [c] -- so show_ 'd' = "d". You can put show_ = show if you want "'d'"
showList_ = id -- just return the string
In practice:
Now that's not much use to hide " from your output in ghci, because the default show function is used for that, but if we use putStrLn, the quotes disappear:
put :: Show_ a => a -> IO ()
put = putStrLn . show_
ghci> show "hello"
"\"hello\""
ghci> show_ "hello"
"hello"
ghci> put "hello"
hello
ghci> put [2,3,4]
[2, 3, 4]
ghci>

Related

Differentiate between String and [Char]

I know that String is defined as [Char], yet I would like to make a difference between the two of them in a class instance. Is that possible with some clever trick other than using newtype to create a separate type? I would like to do something like:
class Something a where
doSomething :: a -> a
instance Something String where
doSomething = id
instance (Something a) => Something [a] where
doSomething = doSoemthingElse
And get different results when I call it with doSomething ("a" :: [Char]) and doSomething ("a" :: String).
I do know about FlexibleInstances and OverlappingInstances but they obviously don't cut the case.
That is not possible. String and [Char] are the same type. There is no way to distinguish between the two types. With OverlappingInstances you can create separate instances for String and [a], but [Char] will always use the instance for String.
Why don't you define functions for each case:
doSomethingString :: String -> String
doSomethingString = id
doSomethingChars :: (Char -> Char) -> String -> String
doSomethingChars f = ...
As said before, String and [Char] IS effectively the same.
What you can do though is defining a newtype. It wraps a type (at no-cost as it is completely removed when compiled) and makes it behave like a different type.
newtype Blah = Blah String
instance Monoid Blah where
mempty = Blah ""
mappend (Blah a) (Blah b) = Blah $ a ++ "|" ++ b

Haskell: list of elements with class restriction

here's my question:
this works perfectly:
type Asdf = [Integer]
type ListOfAsdf = [Asdf]
Now I want to do the same but with the Integral class restriction:
type Asdf2 a = (Integral a) => [a]
type ListOfAsdf2 = (Integral a) => [Asdf2 a]
I got this error:
Illegal polymorphic or qualified type: Asdf2 a
Perhaps you intended to use -XImpredicativeTypes
In the type synonym declaration for `ListOfAsdf2'
I have tried a lot of things but I am still not able to create a type with a class restriction as described above.
Thanks in advance!!! =)
Dak
Ranting Against the Anti-Existentionallists
I always dislike the anti-existential type talk in Haskell as I often find existentials useful. For example, in some quick check tests I have code similar to (ironically untested code follows):
data TestOp = forall a. Testable a => T String a
tests :: [TestOp]
tests = [T "propOne:" someProp1
,T "propTwo:" someProp2
]
runTests = mapM runTest tests
runTest (T s a) = putStr s >> quickCheck a
And even in a corner of some production code I found it handy to make a list of types I'd need random values of:
type R a = Gen -> (a,Gen)
data RGen = forall a. (Serialize a, Random a) => RGen (R a)
list = [(b1, str1, random :: RGen (random :: R Type1))
,(b2, str2, random :: RGen (random :: R Type2))
]
Answering Your Question
{-# LANGUAGE ExistentialQuantification #-}
data SomeWrapper = forall a. Integral a => SW a
If you need a context, the easiest way would be to use a data declaration:
data (Integral a) => IntegralData a = ID [a]
type ListOfIntegralData a = [IntegralData a]
*Main> :t [ ID [1234,1234]]
[ID [1234,1234]] :: Integral a => [IntegralData a]
This has the (sole) effect of making sure an Integral context is added to every function that uses the IntegralData data type.
sumID :: Integral a => IntegralData a -> a
sumID (ID xs) = sum xs
The main reason a type synonym isn't working for you is that type synonyms are designed as
just that - something that replaces a type, not a type signature.
But if you want to go existential the best way is with a GADT, because it handles all the quantification issues for you:
{-# LANGUAGE GADTs #-}
data IntegralGADT where
IG :: Integral a => [a] -> IntegralGADT
type ListOfIG = [ IntegralGADT ]
Because this is essentially an existential type, you can mix them up:
*Main> :t [IG [1,1,1::Int], IG [234,234::Integer]]
[IG [1,1,1::Int],IG [234,234::Integer]] :: [ IntegralGADT ]
Which you might find quite handy, depending on your application.
The main advantage of a GADT over a data declaration is that when you pattern match, you implicitly get the Integral context:
showPointZero :: IntegralGADT -> String
showPointZero (IG xs) = show $ (map fromIntegral xs :: [Double])
*Main> showPointZero (IG [1,2,3])
"[1.0,2.0,3.0]"
But existential quantification is sometimes used for the wrong reasons,
(eg wanting to mix all your data up in one list because that's what you're
used to from dynamically typed languages, and you haven't got used to
static typing and its advantages yet).
Here I think it's more trouble than it's worth, unless you need to mix different
Integral types together without converting them. I can't see a reason
why this would help, because you'll have to convert them when you use them.
For example, you can't define
unIG (IG xs) = xs
because it doesn't even type check. Rule of thumb: you can't do stuff that mentions the type a on the right hand side.
However, this is OK because we convert the type a:
unIG :: Num b => IntegralGADT -> [b]
unIG (IG xs) = map fromIntegral xs
Here existential quantification has forced you convert your data when I think your original plan was to not have to!
You may as well convert everything to Integer instead of this.
If you want things simple, keep them simple. The data declaration is the simplest way of ensuring you don't put data in your data type unless it's already a member of some type class.

Removing backslashes when show Strings?

I have parametric method which concats a String onto a parametric input:
foo::(Show a) => a -> String
foo f = show f ++ " string"
it is fine when I don pass in a string, but when I pass in a string I get extra blackslashes.
is there a way i avoid ths?
show is not really a toString equivalent but rather an inspect or var_dump equivalent. It's not meant for formatting for human output.
You might consider http://hackage.haskell.org/package/text-format
Don't know about "standard" library function but can be simply done with own show-like implementation:
class StrShow a where
showStr :: a -> String
instance StrShow String where
showStr = id
instance Show a => StrShow a where
showStr = show
GHCi> showStr 1
"1"
GHCi> showStr "hello"
"hello"
This way you don't need extra library but have to use lot of ghc's extensions (TypeSynonymInstances, FlexibleInstances, UndecidableInstances, OverlappingInstances) if this is not an issue.
One way of doing this, which isn't very nice but it's certainly possible, is to use the Typeable class.
import Data.Maybe (fromMaybe)
import Data.Typeable (cast)
foo :: (Show a, Typeable a) => a -> String
foo f = fromMaybe (show f) (cast f)
However, this restricts it to members of the Typeable class (which is included in base, so you won't need to depend on any more libraries, and most things will have defined it).
This works by checking if f is a String (or pretending to be a String, which will only happen if someone's been REALLY evil when writing a library), and if it is, returning it, otherwise showing it.

Is there a polymorphic `toString` function that doesn't add quotes?

In most OO languages that I'm familiar with, the toString method of a String is actually just the identity function. But in Haskell show adds double quotes.
So if I write a function something like this
f :: Show a => [a] -> String
f = concat . map show
it works as expected for numbers
f [0,1,2,3] -- "0123"
but Strings end up with extra quotes
f ["one", "two", "three"] -- "\"one\"\"two\"\"three\""
when I really want "onetwothree".
If I wanted to write f polymorphically, is there a way to do it with only a Show constraint, and without overriding the Show instance for String (if that's even possible).
The best I can come up with is to create my own type class:
class (Show a) => ToString a where
toString = show
and add an instance for everything?
instance ToString String where toString = id
instance ToString Char where toString = pure
instance ToString Int
instance ToString Maybe
...etc
I think the root cause of your problem is that show isn't really renderToText. It's supposed to produce text that you could paste into Haskell code to get the same value, or convert back to the same value using read.
For that purpose, show "foo" = "foo" wouldn't work, because show "1" = "1" and show 1 = "1", which loses information.
The operation you want to be able to apply to "foo" to get "foo" and to 1 to get "1" is something other than show. show just isn't a Java-esque toString.
When I've needed this before, I have indeed made my own new type class and made a bunch of things instances of it, and then used that rather than Show. Most of the instances were implemented with show, but String wasn't the only one I wanted to customise so the separate type class wasn't completely wasted. In practice, I found there were only a handful of types that I actually needed the instance for, and it was pretty trivial to add them as I got compile errors.
The Pretty class and its corresponding type Doc have the needed behavior for Show. Your link shows a different use case, however; maybe you could edit the question?
You could do this:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
class Show a => ToString a where
toString :: a -> String
instance Show a => ToString a where
toString = show
instance ToString String where
toString = id
Prelude> toString "hello"
"hello"
Prelude> toString 3
"3"
Note that this is probably a terrible idea.
You could use newtype with OverloadedStrings:
{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
newtype LiteralString = LS ByteString
instance IsString LiteralString where fromString = LS . B.pack
instance Show LiteralString where show (LS x) = B.unpack x
instance Read LiteralString where readsPrec p s = map (\(!s, !r) -> (LS s,r)) $! readsPrec p s
hello :: LiteralString
hello = "hello world"
main :: IO ()
main = putStrLn . show $! hello
output:
hello world
The double quotes in the normal case are actually useful when reading a shown string back in the context of larger expression as they clearly delimit shown string values from values of other shown types:
x :: (ByteString, Int)
x = read . show $! ("go", 10)
-- string value starts --^^-- ends
y :: (LiteralString, Int)
y = read . show $! ("go", 10)
-- string value starts --^ ^ consumes all characters; read fails

"enable_if" in Haskell

How do I write something like the following in Haskell:
showSquare :: (Show a, Num a) => a -> String
showSquare x = "The square of " ++ (show x) ++ " is " ++ (show (x * x))
showSquare :: (Show a, not Num a) => a -> String
showSquare x = "I don't know how to square " ++ (show x)
Basically, something like boost::enable_if in C++.
GHC extensions are ok.
Why would you want this? The typechecker makes sure that you will never call showSquare on something which isn't a Num in the first case. There is no instanceof in Haskell, as everything is typed statically.
It doesn't work for arbitrary types: you can only define your own type class, e.g.
class Mine a where
foo :: a -> String
instance (Num a) => Mine a where
foo x = show x*x
And you can add more instances for other classes, but you won't be able to write just instance Mine a for an arbitrary a. An additional instance (Show a) => ... will also not help, as overlapping instances are also not allowed (the link describes a way to work around it, but it requires quite a bit of additional machinery).
First, giving different type signature to different equations for the same function isn't possible at all. Any function can have only one type, regardless of how much equations it has.
Second, negative constraints does not (would not) have any sound meaning in Haskell. Recall what class constraint mean:
f :: Num a => a -> a -> a
f x y = x + y
Num a in the type of f means that we can apply any class methods of Num type class to values of type a. We are consciously not naming concrete type in order to get generic behavior. Essentially, we are saying "we do not care what a exactly is, but we do know that Num operations are applicable to it". Consequently, we can use Num methods on x and y, but no more than that, that is, we cannot use anything except for Num methods on x and y. This is what type class constraints are and why are they needed. They are specifying generic interface for the function.
Now consider your imaginary not Num a constraint. What information does this statement bring? Well, we know that a should not be Num. However, this information is completely useless for us. Consider:
f :: not Num a => a -> a
f = ???
What can you place instead of ???? Obviously, we know what we cannot place. But except for that this signature has no more information than
f :: a -> a
and the only operation f could be is id (well, undefined is possible too, but that's another story).
Finally consider your example:
showSquare :: (Show a, not Num a) => a -> String
showSquare x = "I don't know how to square " ++ (show x)
I do not give first part of your example intentionally, see the first sentence in my answer. You cannot have different equations with different types. But this function alone is completely useless. You can safely remove not Num a constraint here, and it won't change anything.
The only usage for such negative constrains in statically typed Haskell is producing compile-time errors when you supply, say, Int for not Num a-constrainted variable. But I see no use for this.
If I really, absolutely needed something like this (and I don't believe I ever have), I think this is the simplest approach in Haskell:
class Show a => ShowSquare a where
showSquare :: a -> String
showSquare a = "I don't know how to square " ++ (show a)
instance ShowSquare Int where
showSquare = showSquare'
instance ShowSquare Double where
showSquare = showSquare'
-- add other numeric type instances as necessary
-- make an instance for everything else
instance Show a => ShowSquare a
showSquare' :: (Show a, Num a) => a -> String
showSquare' x = "The square of " ++ (show x) ++ " is " ++ (show (x * x))
This requires overlapping instances, obviously. Some people may complain about the required boilerplate, but it's pretty minimal. 5 or 6 instances would cover most numeric numeric types.
You could probably make something work using ideas from the Advanced Overlap wiki page. Note that technique still requires instances to be listed explicitly, so whether it's better than this is probably a matter of taste.
It's also possible to approach the problem with template haskell, by writing a TH splice instead of a function. The splice would have to reify ''Num at the call site to determine if a Num instance is in scope, then choose the appropriate function. However, making this work is likely to be more trouble than just writing out the Num instances manually.
Depending on "not a Num a" is very fragile in Haskell in a way that is not fragile in C++.
In C++ the classes are defined in one placed (closed) while Haskell type classes are open and can have instances declared in module C of data from module A and class from module B.
The (no extension) resolution of type classes has a guiding principle that importing a module like "C" would never change the previous resolution of type classes.
Code that expected "not a Num Custom" will change if any recursively imported module (e.g. from another package) defined an "instance Num Custom".
There is an additional problem with polymorphism. Consider a function in module "D"
useSS :: Show a => a -> Int -> [String]
useSS a n = replicate n (showSquare a)
data Custom = Custom deriving Show
use1 :: Int -> String
use1 = useSS Custom -- no Num Custom in scope
Now consider a module "E" in another package which imports the above module "D"
instance Num Custom
use2 :: Int -> String
use2 = useSS Custom -- has a Num Custom now
What should (use1 1) and (use2 1) evaluate to? Do you want to work with a language with traps like this? Haskell is trying to prevent, by principled design, the existence of this trap.
This kind of ad hoc overloading is everywhere in C++ resolution but is exactly what Haskell was designed to avoid. It is possible with GHC extensions to do such things, but one has to be careful not to create dangerous traps, and it is not encouraged.

Resources