能否为饱和状态的(->) a b编写含类型信息的通用Show实例?
通用Show实例用于饱和函数类型
当然可以!你完全不用手动为每一种a -> b的类型组合编写Show实例——借助Haskell的Typeable类型类和几个语言扩展,就能实现一个通用的解决方案,自动提取并展示函数的类型信息。
实现步骤
首先需要启用几个必要的语言扩展:
FlexibleInstances:允许我们为带参数的类型(比如(->) a b)定义实例ScopedTypeVariables+TypeApplications:让我们能在实例中明确指定要获取类型信息的类型参数
然后结合Data.Typeable模块提供的typeRep函数,就能写出通用的Show实例:
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} import Data.Typeable (Typeable, typeRep) instance (Typeable a, Typeable b) => Show ((->) a b) where show _ = show (typeRep @a) ++ " -> " ++ show (typeRep @b)
代码解释
Typeable类型类是Haskell的“运行时类型信息”机制,它允许我们在运行时获取类型的表示。几乎所有标准库类型都自动派生了Typeable,自定义类型只需要加上deriving Typeable即可。typeRep @a会生成对应a类型的TypeRep值,这个值本身带有Show实例,能直接转换成可读性强的类型字符串。- 我们在
show函数里忽略了函数参数_——因为Haskell中普通函数本身是不可序列化/展示的,而你的需求只关注类型信息,所以这完全符合预期。
测试示例
现在来验证一下效果:
*Main> f = id :: Int -> Int *Main> f Int -> Int *Main> g = length :: String -> Int *Main> g [Char] -> Int *Main> h = (+) :: Integer -> Integer -> Integer *Main> h Integer -> Integer -> Integer -- 自定义类型的情况 *Main> data MyType = MyVal deriving (Typeable, Show) *Main> k = (\x -> MyVal) :: Bool -> MyType *Main> k Bool -> MyType
注意事项
- 这个通用实例会匹配所有满足
Typeable a和Typeable b的函数类型。如果你之后需要为某一特定函数类型编写自定义Show实例,只需要写出更具体的实例即可——Haskell的实例匹配规则会优先选择最具体的实例。 - 对于没有派生
Typeable的类型,这个实例无法生效,不过你只需要在自定义类型的deriving子句中加上Typeable就能解决。
内容的提问来源于stack exchange,提问作者Michiel Borkent
相关产品推荐
相关产品推荐

