我想定义一个转换为字符串的函数,例如以下' toString':
show 1 = "1"
show True = "True"
show "1" = "\"1\""
请注意'显示'不这样做。相比之下,它做了以下几点:
import Data.Typeable
toString a :: (Show a) => a -> String
toString a
| typeOf a == typeOf "" = a
| otherwise = show a
也就是说,它会在字符串周围添加额外的引号。在这种情况下,如果我已经有一个字符串,我不想添加额外的引号。
我考虑使用类似的东西:
ui-block-a
在做这种奇怪的基于类型的条件时是否有任何陷阱?是否有一些内置的Haskell函数可以更好地使用?
答案 0 :(得分:6)
这种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
然后,您的函数为makeString :: Print a => a -> String
,并且它具有一个具有Show
实例的所有实例。要拥有第二个实例,您需要FlexibleInstances
(实例头不是通常的形式)和UndecideableInstances
(因为约束与实例头一样通用,GHC无法确定它不会陷入试图解决这些约束的无限循环中。)
答案 1 :(得分:4)
如果您想要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
答案 2 :(得分:2)
将OP解决方案尝试扩展到工作中:
import Data.Typeable
toString :: (Show a, Typeable a) => a -> String
toString x = case cast x of
Just y -> y
Nothing -> show x