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

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

Related

Function that can be called on Strings and Int. Ambiguous type variable problem

I want to write a function that can be called on numbers (e.g. 1) and on strings (e.g. "a"). It is important in my application to simplify "user code" as much as possible.
The minimal example of my code looks like this
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
type StrInt = Either String Int
class Lift a where
toStrInt :: a -> StrInt
instance Lift String where
toStrInt= Left
instance Lift Int where
toStrInt= Right
declare:: StrInt ->String
declare (Left a) = "String: " ++ a
declare (Right n) = "Number: " ++ (show n)
declare' :: Lift a => a -> String
declare' a = declare (toStrInt a)
myDecA = declare' "a"
myDec1 = declare' 1
Compiling this gives the error
Ambiguous type variable ‘a0’ arising from a use of ‘declare'’
prevents the constraint ‘(Lift a0)’ from being solved.
I understand the problem and I know that I can replace the last line with any of the following:
myDec1 = declare' (1::Int)
myDec1 = declare (Right 1)
But that defeats the purpose of what I'm trying to achieve. Is there a clever way of setting the same idea such that it makes clear that 1 is an Int?
Also, In my application (more complex than the minimal example above) The declare function only works for Int s. So I can't generalize it for all Num a.
This is not possible using Haskell. The reason for this is that while 1 looks like an Int, it's actually a Num a => a. Haskell does not have a way to know that Int is the only a that satisfies (Num a, Lift a) => a, so it needs to be told this explicitly. For example, if I create in another module the following instance:
instance Num String where
...
Then declare' 1 becomes ambiguous, and could reasonably result in either "String:..." or "Int:...". Haskell can't know at compile time that I won't do this, so we have a problem.
Like I said in my comment, this is a hacky solution. There might be a cleaner way.
But what you can do is enable OverloadedStrings and then make NumStr an instance of IsString and Num so that you can convert literals to it.
{-# LANGUAGE OverloadedStrings #-}
module Hacky where
import Data.String (IsString(..))
newtype StrInt = StrInt (Either String Int)
instance IsString StrInt where
fromString str = StrInt (Left str)
instance Num StrInt where
-- fromIntegral is to convert 'Integer' to 'Int'.
fromInteger n = StrInt (Right (fromIntegral n))
-- other methods for 'Num' are missing...
declare :: StrInt -> String
declare (StrInt (Left a)) = "String: " ++ a
declare (StrInt (Right n)) = "Number: " ++ show n
main :: IO ()
main = do
putStrLn $ declare "hi"
putStrLn $ declare 1
Note that I didn't implement the other required methods for Num, which you may wish to do, otherwise code like declare (1 + 3) won't typecheck.
I'd be happier with this if there was something like OverloadedNumbers, but I couldn't find a pragma like that.

How to avoid default return value when accessing a non-existent field with lenses?

I love Lens library and I love how it works, but sometimes it introduces so many problems, that I regret I ever started using it. Lets look at this simple example:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Data = A { _x :: String, _y :: String }
| B { _x :: String }
makeLenses ''Data
main = do
let b = B "x"
print $ view y b
it outputs:
""
And now imagine - we've got a datatype and we refactor it - by changing some names. Instead of getting error (in runtime, like with normal accessors) that this name does not longer apply to particular data constructor, lenses use mempty from Monoid to create default object, so we get strange results instead of error. Debugging something like this is almost impossible.
Is there any way to fix this behaviour? I know there are some special operators to get the behaviour I want, but all "normal" looking functions from lenses are just horrible. Should I just override them with my custom module or is there any nicer method?
As a sidenote: I want to be able to read and set the arguments using lens syntax, but just remove the behaviour of automatic result creating when field is missing.
It sounds like you just want to recover the exception behavior. I vaguely recall that this is how view once worked. If so, I expect a reasonable choice was made with the change.
Normally I end up working with (^?) in the cases you are talking about:
> b ^? y
Nothing
If you want the exception behavior you can use ^?!
> b ^?! y
"*** Exception: (^?!): empty Fold
I prefer to use ^? to avoid partial functions and exceptions, similar to how it is commonly advised to stay away from head, last, !! and other partial functions.
Yes, I too have found it a bit odd that view works for Traversals by concatenating the targets. I think this is because of the instance Monoid m => Applicative (Const m). You can write your own view equivalent that doesn't have this behaviour by writing your own Const equivalent that doesn't have this instance.
Perhaps one workaround would be to provide a type signature for y, so know know exactly what it is. If you had this then your "pathological" use of view wouldn't compile.
data Data = A { _x :: String, _y' :: String }
| B { _x :: String }
makeLenses ''Data
y :: Lens' Data String
y = y'
You can do this by defining your own view1 operator. It doesn't exist in the lens package, but it's easy to define locally.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Data = A { _x :: String, _y :: String }
| B { _x :: String }
makeLenses ''Data
newtype Get a b = Get { unGet :: a }
instance Functor (Get a) where
fmap _ (Get x) = Get x
view1 :: LensLike' (Get a) s a -> s -> a
view1 l = unGet . l Get
works :: Data -> String
works = view1 x
-- fails :: Data -> String
-- fails = view1 y
-- Bug.hs:23:15:
-- No instance for (Control.Applicative.Applicative (Get String))
-- arising from a use of ‘y’

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

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>

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.

overload show for list

I want a newline-separated representation instead of the usual comma separated one, for may new data tyepe:
newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer)
deriving (Show)
I tried to write this istance of Show class :
instance Show [SimpleRecord] where
show [(SimpleRecord (n, i, c))] = show (SimpleRecord (n, i, c))++['\n']
show (l:ls) = (show l)++['\n']++(show ls)
GHC heavily insults me.
Can someone try to explain me what can I do?
First, the Show class is supposed to be for producing Haskell source code, which the Read class can then read back in. It isn't supposed to be for producing human-readable, "pretty" output.
Having just said that, almost everyone misuses it for the latter, and it can be helpful for debugging purposes.
So, your options are:
Write some function not called show which does what you want. (As per AndrewC's comment.)
Use the showList method.
If you write deriving Show, this tells the compiler to write all the Show methods for you. If you want to write them yourself, you need to take away the deriving bit first. Then you can write your instance, which is going to look something like
instance Show SimpleRecord where
show (SimpleRecord (x, y, z)) = ...
showList rs = unlines (map show rs)
As an aside, if you didn't already know this, you can write
mapM_ print records
at the GHCi prompt to print out any list of printable things with one element per line.
As a final asside, why
newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer)
rather than
data SimpleRecord = SimpleRecord [Char] [Char] Integer
Your question is quite ambiguos. If I interpret correctly you are trying to change the default Show instance for [SimpleRecord].
As GHC has already defined the instance Show [a] when Show a is defined. You get following error (after including FlexibleInstances extension) when you try to again define instance for Show [SimpleRecord].
Matching instances:
instance Show a => Show [a] -- Defined in `GHC.Show'
instance Show [SimpleRecord] -- Defined at show.hs:5:11
So you need to use OverlappingInstances language extension to allow overloading it.
It states GHC to match the most specific instance.
You might also want to include FlexibleInstances extension, which allows to mention arbitrary nested types in instance declaration..
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer)
deriving (Show)
instance Show [SimpleRecord] where
show [SimpleRecord (n, i, c)] = show (SimpleRecord (n, i, c))++"\n"
show (l:ls) = show l ++ "\n" ++ show ls
You get get more information about these language extensions at GHC Docs
Just a comment on design of your type, It is better to define your type as
data SimpleRecord = SimpleRecord String String Integer
You get more flexibility here in terms of partial constructor application etc.
I might have been missing something, but it wasn't clear why you were newtyping (String,String,Integer) rather than what you were concerned to show nicely, namely lists of them. Then you would evade the universal Show instance for lists:
newtype SimpleRecords = SimpleRecords [(String, String, Integer)]
instance Show SimpleRecords where
show (SimpleRecords []) = ""
show (SimpleRecords ((n, i, c): xs)) =
show (n, i, c) ++ "\n" ++ show (SimpleRecords xs)
-- Prelude Main> let a = words "We hold these truths to be self-evident"
-- Prelude Main> let b = words "All the best people are using Clorox"
-- Prelude Main> let c = zip3 a b [1::Integer ..]
-- Prelude Main> SimpleRecords c
-- ("We","All",1)
-- ("hold","the",2)
-- ("these","best",3)
-- ("truths","people",4)
-- ("to","are",5)
-- ("be","using",6)
-- ("self-evident","Clorox",7)

Resources