How to convert arbitrary type to string, without adding extra quotes to strings?

拟墨画扇 提交于 2020-12-12 02:05:11

问题


I want to define a function which converts to strings, like the following 'toString':

toString 1 = "1"
toString True = "True"
toString "1" = "1"

Note that 'show' does not do this. By contrast it does the following:

show 1 = "1"
show True = "True"
show "1" = "\"1\""

That is, it adds extra quotes around strings. In this case I don't want to add extra quotes if I already have a string.

I'm considering using something like:

import Data.Typeable

toString a :: (Show a) => a -> String
toString a
  | typeOf a == typeOf "" = a
  | otherwise = show a

Are there any pitfalls in doing such a weird type-based conditional? Is there some built-in Haskell function that would be better to use instead?


回答1:


This sort of ad-hoc polymorphism is permitted through type-classes. However, they will have to be overlapping since you want a catch all case:

{-# LANGUAGE FlexibleInstances, UndecideableInstances #-}

class Print a where
  makeString :: a -> String

instance {-# OVERLAPPING #-} Print String where
  makeString s = s

instance Show a => Print a where
  makeString x = show x

Then, your function is makeString :: Print a => a -> String and it has an instance for everything that has a Show instance. To have the second instance, you need FlexibleInstances (the instance head is not of the usual form) and UndecideableInstances (since the constraint is as general as the instance head, GHC can't be sure that it won't fall into an infinite loop trying to solve these constraints).




回答2:


If you want something like Alec's approach without overlapping instances, you can get it with a type family.

{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, ScopedTypeVariables, UndecidableInstances, FlexibleInstances, DataKinds, ... whatever else GHC tells you it needs #-}

import Data.Text (Text, unpack)
import Data.Proxy

class Print a where
  makeString :: a -> String

data Name = NString | NText | NShow
type family Choose a where
  Choose [Char] = 'NString
  Choose Text = 'NText
  Choose _ = 'NShow

class Print' (n :: Name) a where
  makeString' :: proxy n -> a -> String

instance (Choose a ~ n, Print' n a) => Print a where
  makeString = makeString' (Proxy :: Proxy n)

instance a ~ String => Print' 'NString a where
  makeString' _ = id

instance a ~ Text => Print' 'NText a where
  makeString' _ = unpack

instance Show a => Print' 'NShow a where
  makeString' _ = show



回答3:


Expanding the OP solution attempt into a working one:

import Data.Typeable

toString :: (Show a, Typeable a) => a -> String
toString x = case cast x of
   Just y  -> y
   Nothing -> show x


来源:https://stackoverflow.com/questions/41095748/how-to-convert-arbitrary-type-to-string-without-adding-extra-quotes-to-strings

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!