存在类型族时无需手动编写约束派生Show实例的实现方法
核心实现方案
利用GHC的DerivingVia扩展配合泛型派生+量化约束,一次性解决所有同结构ADT的实例派生问题,无需为每个字段手动写约束。
1. 开启必要扩展
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE FlexibleContexts #-}
2. 定义通用约束同义词
针对你的Switchable类型族定义通用约束,一次性覆盖所有字段的约束要求:
import GHC.Generics import Data.Kind import Prelude type family Switchable (f :: Type -> Type) x where Switchable TextName x = String Switchable Same x = x data TextName x data Same x -- 通用约束:对于所有满足c的类型x,Switchable f x也满足c type AllSwitchable c f = forall x. c x => c (Switchable f x)
3. ADT定义与自动派生
ADT仅需要派生Generic,然后通过Generically包装器派生你需要的Show/Eq等实例,无需手动写任何字段约束:
data Foo f = Foo { fooField :: Switchable f Int , fooField2 :: Switchable f Bool -- 新增任意Switchable字段都不需要修改派生逻辑 } deriving Generic deriving (Show, Eq) via Generically (Foo f)
4. 为标签类型预制约束实例(可选,进一步简化调用)
针对你使用的TextName和Same标签预制实例,后续使用时无需携带任何额外约束:
-- TextName场景下所有Switchable结果都是String,天然满足Show/Eq等类 instance AllSwitchable Show TextName instance AllSwitchable Eq TextName -- Same场景下Switchable结果等于原类型,约束直接透传 instance AllSwitchable Show Same instance AllSwitchable Eq Same
效果验证
直接使用无需额外声明约束:
main = do print $ Foo @TextName 123 True -- 输出Foo {fooField = "123", fooField2 = "True"} print $ Foo @Same 123 True -- 输出Foo {fooField = 123, fooField2 = True}
内容的提问来源于stack exchange,提问作者tom
相关产品推荐
相关产品推荐

