如何将任意类型转换为字符串,而不向字符串添加额外的引号?

mhe*_*rzl 1 haskell

我想定义一个转换为字符串的函数,如下面的'toString':

toString 1 = "1"
toString True = "True"
toString "1" = "1"
Run Code Online (Sandbox Code Playgroud)

请注意,'show'不会这样做.相比之下,它做了以下事情:

show 1 = "1"
show True = "True"
show "1" = "\"1\""
Run Code Online (Sandbox Code Playgroud)

也就是说,它会在字符串周围添加额外的引号.在这种情况下,如果我已经有一个字符串,我不想添加额外的引号.

我正在考虑使用类似的东西:

import Data.Typeable

toString a :: (Show a) => a -> String
toString a
  | typeOf a == typeOf "" = a
  | otherwise = show a
Run Code Online (Sandbox Code Playgroud)

做这种奇怪的基于类型的条件是否有任何陷阱?是否有一些内置的Haskell功能可以更好地使用?

Ale*_*lec 5

通过类型类允许这种ad-hoc多态.但是,它们必须重叠,因为您需要捕获所有情况:

{-# 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
Run Code Online (Sandbox Code Playgroud)

然后,你的函数是makeString :: Print a => a -> String,它有一个实例,包含一个Show实例.要拥有第二个实例,你需要FlexibleInstances(实例头不是通常的形式)和UndecideableInstances(因为约束和实例头一样通用,GHC不能确定它不会陷入无限循环试图解决这些限制).


dfe*_*uer 5

如果您想要像 Alec 的方法而不重叠实例,您可以使用类型系列来获得它。

{-# 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
Run Code Online (Sandbox Code Playgroud)


chi*_*chi 5

将 OP 解决方案尝试扩展为可行的解决方案:

import Data.Typeable

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