我想使用某些类型系列将任何类型转换为类型级别的字符串。
当然,我可以这样写:
type family ShowType (t :: Type) :: Symbol where
ShowType Int = "Int"
ShowType String = "String"
...
但我想知道是否有一些现有的机制呢?我可以使用Typeable
技术在运行时执行此操作。但是如何自动将任何类型转换为Symbol
?
答案 0 :(得分:1)
对于所有类型,都没有通用的解决方案。但也许你会发现以下有趣的东西。
您可以获取具有Generic
实例的类型构造函数的名称,但这会排除Int
和Float
等基本类型。下面给出了两种不同的方式:
{-# LANGUAGE AllowAmbiguousTypes#-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
import Data.Proxy
import GHC.Generics
import GHC.TypeLits
-- Solution 1: Defines a type family that extracts the type
-- constructor name as a Symbol from a generic Rep.
-- Then it can be reified via GHC.TypeLits.symbolVal.
type family TyConName (f :: * -> *) :: Symbol where
TyConName (M1 D ('MetaData name _mdl _pkg _nt) _f) = name
tyConName
:: forall a s
. (Generic a, s ~ TyConName (Rep a), KnownSymbol s) => String
tyConName = symbolVal (Proxy @s)
-- Solution 2: Uses the GHC.Generics.datatypeName helper
-- (value-level string only).
tyConName'
:: forall a d f p
. (Generic a, Rep a ~ D1 d f, Datatype d) => String
tyConName' = datatypeName (from @a undefined)
main = do
print (tyConName @(Maybe Int)) -- "Maybe"
print (tyConName' @(Maybe Int)) -- "Maybe"