Is there a polymorphic `toString` function that does not add quotes?

In most OO languages ​​that I'm familiar with, the toString String method is actually just an identification function. But in Haskell show , double quotes are added.

So, if I write some function, then

 f :: Show a => [a] -> String f = concat . map show 

works as expected for numbers

 f [0,1,2,3] -- "0123" 

but lines end with extra quotation marks

 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 this only with the show constraint and without overriding the Show instance for String (if possible).

The best I can come up with is to create my own class like:

 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 
+6
source share
4 answers

I think the main reason for your problem is that show is not really renderToText . It should create text that you could insert into Haskell code to get the same value, or convert back to the same value with read .

To this end, show "foo" = "foo" will not work because show "1" = "1" and show 1 = "1" , which is losing information.

The operation you want to apply to "foo" to get "foo" and 1 to get "1" is something other than show . show simply not Java-esque toString .

When I needed it before, I really created my new type class and created a bunch of instances, and then used that, not show . Most of the instances were implemented using show , but String was not the only one I wanted to configure, so the separate class type was not completely lost. In practice, I found that there are only a few types for which I really need an instance, and it was pretty trivial to add them since I got compilation errors.

+7
source

The Pretty class and its corresponding Doc type have the necessary behavior for Show. However, your link shows a different use case; maybe you could edit the question?

+5
source

You can do it:

 {-# 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" 

Please note that this is probably a terrible idea.

+3
source

You can 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 ps = map (\(!s, !r) -> (LS s,r)) $! readsPrec ps hello :: LiteralString hello = "hello world" main :: IO () main = putStrLn . show $! hello 

exit:

 hello world 

Double quotes in the normal case are really useful when reading the displayed string in the context of a larger expression, since they explicitly limit the displayed string values ​​from the values ​​of other display 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 
+2
source

Source: https://habr.com/ru/post/923921/


All Articles