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

如何检查字段类型为类型级计算结果的Haskell记录?

从Servant的Server类型中提取记录字段的最终类型

你可以通过类型级编程结合GHC泛型实现需求——直接从Server API类型中提取所有记录字段的具体类型,无需逐个指定字段。以下是两种可行方案:

方案1:针对特定记录类型的直接实现

如果仅需处理Counter这类特定记录类型,可直接为其定义类型家族,明确提取字段类型:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
import Servant

-- 定义类型类,关联记录的字段类型列表
class RecordFieldTypes a where
  type FieldTypes a :: [*]

-- 为Counter的实例实现类型类
instance RecordFieldTypes (Counter m) where
  type FieldTypes (Counter m) = 
    [ m :- Capture "stuff" Int :> PostNoContent
    , m :- Get '[JSON] Int
    ]

使用时直接查询类型即可:

ghci> :kind! FieldTypes (Server API)
FieldTypes (Server API) :: [*]
= '[AsServerT Handler :- Capture "stuff" Int :> PostNoContent, AsServerT Handler :- Get '[JSON] Int]

方案2:通用泛型实现(支持所有派生Generic的记录)

如果需要处理任意通过NamedRoutes定义的记录类型,可利用GHC泛型在类型层面遍历记录结构,自动提取所有字段类型:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
import Servant

-- 内部类型类,处理泛型Rep的结构
class GRecordFieldTypes f where
  type GFieldTypes f :: [*]

-- 忽略数据类型的元信息
instance GRecordFieldTypes (M1 D x f) where
  type GFieldTypes (M1 D x f) = GFieldTypes f

-- 忽略构造器的元信息
instance GRecordFieldTypes (M1 C x f) where
  type GFieldTypes (M1 C x f) = GFieldTypes f

-- 提取单个字段的类型
instance GRecordFieldTypes (M1 S x (K1 R a)) where
  type GFieldTypes (M1 S x (K1 R a)) = '[a]

-- 组合多个字段的类型列表
instance (GRecordFieldTypes f, GRecordFieldTypes g) => GRecordFieldTypes (f :*: g) where
  type GFieldTypes (f :*: g) = GFieldTypes f ++ GFieldTypes g

-- 顶层类型类,对接Generic
class RecordFieldTypes a where
  type FieldTypes a :: [*]

instance (Generic a, GRecordFieldTypes (Rep a)) => RecordFieldTypes a where
  type FieldTypes a = GFieldTypes (Rep a)

这个方案无需为每个记录类型单独写实例,只要记录派生了Generic(比如示例中的Counter),就能自动提取字段类型:

ghci> :kind! FieldTypes (Server API)
FieldTypes (Server API) :: [*]
= '[AsServerT Handler :- Capture "stuff" Int :> PostNoContent, AsServerT Handler :- Get '[JSON] Int]

两种方案都能在类型层面完成计算,你可以根据是否需要通用性选择合适的实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 03:15:32