You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取HasField类型类的全部实例(含GHC自动生成实例)

获取Haskell记录类型的所有HasField实例(含自动生成)

1. 在GHCi中查看自动生成的HasField实例

GHC为记录字段自动生成的HasField实例属于派生隐含实例,默认不会出现在:instances命令的输出里。需要开启两个编译选项:

  • 在GHCi中执行:
    :set -fprint-explicit-kinds -fprint-deriving-instances
    

之后再查询具体实例,比如:

:instances HasField "f1" R

就能看到GHC自动生成的HasField "f1" R Int实例,以及手动定义的实例。

2. 用Template Haskell获取所有HasField实例

默认的reify ''HasField只能收集到显式手动定义的实例,要获取自动生成的实例,需要调整编译选项并使用reifyInstances函数:

必要的编译选项

  • 开启扩展:TemplateHaskell、DataKinds、GHC.Records(引入HasField类型类)
  • 编译时添加-fprint-deriving-instances,让GHC把派生的实例暴露给Template Haskell

示例代码

{-# LANGUAGE TemplateHaskell, DataKinds, GHC.Records #-}
import Language.Haskell.TH
import GHC.Records (HasField(..))

-- 定义记录类型,GHC自动为f1、f2生成HasField实例
data R = R { f1 :: Int, f2 :: String } deriving (Show)

-- 手动定义的HasField实例
instance HasField "f3" R Bool where
  getField _ = True

-- 获取指定字段的HasField实例(含自动生成)
getHasFieldInstance :: String -> Q [InstanceDec]
getHasFieldInstance fieldName =
  reifyInstances ''HasField
    [ ConT ''R
    , LitT (StrTyLit fieldName)
    -- 用WildCardT匹配任意字段类型,部分GHC版本支持
    , WildCardT
    ]

-- 批量获取R类型的所有HasField实例(自动+手动)
getAllRHasFieldInstances :: Q [InstanceDec]
getAllRHasFieldInstances = do
  -- 先获取R的类型信息,提取所有字段名
  tyConInfo <- reify ''R
  let fieldNames = case tyConInfo of
        TyConI (DataD _ _ _ _ [RecC _ fields] _) ->
          map (\(fieldName, _, _) -> nameBase fieldName) fields
        _ -> []
  -- 加上手动定义的字段名(比如"f3")
  let allFields = fieldNames ++ ["f3"]
  -- 批量查询每个字段的实例
  concat <$> mapM getHasFieldInstance allFields

注意事项

  • 如果在GHCi中加载该模块,必须先执行:set -fprint-deriving-instances再:load,否则Template Haskell无法获取自动生成的实例。
  • 若你的GHC版本不支持WildCardT,需要显式传入对应字段的类型构造器(比如ConT ''Int对应f1)。

内容的提问来源于stack exchange,提问作者lsmor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:30:11