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

如何用Haskell的Generics/Data.Data提取newtype信息生成文档表格

你之前无法获取内部类型,是因为constrType函数返回的是构造器所属的外层类型,你反复调用该函数只会循环获取newtype本身的元信息,没有深入到构造器的参数类型层面。

你的需求完全可以通过Data.Data实现,也可以用GHC.Generics实现,两种方案的实现代码如下:

方案1:使用Data.Data(更简洁)

只要为你的newtype派生Data和Typeable实例,即可通过gmapQ遍历构造器的参数,拿到内部包装的类型信息:

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}

import Data.Data
import Data.Int
import Data.Word
import Data.Proxy

data MyRowRepresentation = MyRowRepresentation
  String -- newtype名称
  String -- 包装的内部类型名称
  deriving (Show)

toDocRow :: forall a. Data a => Proxy a -> MyRowRepresentation
toDocRow _ = MyRowRepresentation
  (tyconName $ dataTypeOf (undefined :: a)) -- 取外层newtype的名称
  (show $ head $ gmapQ typeOf (undefined :: a)) -- 取构造器第一个参数的类型(newtype只有一个参数)

-- 你的newtype定义,注意修正你原示例里构造器名和类型名不一致的笔误
newtype MyType0 = MyType0 Int16 deriving (Data, Typeable)
newtype MyType1 = MyType1 Int8 deriving (Data, Typeable)
newtype MyType2 = MyType2 Int32 deriving (Data, Typeable)
newtype MyType3 = MyType3 Word8 deriving (Data, Typeable)

main :: IO ()
main = do
  let table = [
        toDocRow (Proxy :: Proxy MyType0),
        toDocRow (Proxy :: Proxy MyType1),
        toDocRow (Proxy :: Proxy MyType2),
        toDocRow (Proxy :: Proxy MyType3)
      ]
  print table
  -- 后续可以把table转为markdown表格写入文件

运行后输出的结构和你需要的完全一致:

[MyRowRepresentation "MyType0" "Int16",MyRowRepresentation "MyType1" "Int8",MyRowRepresentation "MyType2" "Int32",MyRowRepresentation "MyType3" "Word8"]

方案2:使用GHC.Generics

如果你偏好使用GHC.Generics而非Data.Data,可以参考以下实现:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}

import Data.Proxy
import GHC.Generics
import Data.Int
import Data.Word
import Data.Typeable

data MyRowRepresentation = MyRowRepresentation
  String -- newtype名称
  String -- 包装的内部类型名称
  deriving (Show)

class GetDocRow a where
  toDocRow :: Proxy a -> MyRowRepresentation

instance (Generic a, GetDocRowRep (Rep a)) => GetDocRow a where
  toDocRow _ = getDocRowRep (Proxy @(Rep a))

class GetDocRowRep f where
  getDocRowRep :: Proxy f -> MyRowRepresentation

instance (Datatype d, GetDocRowCon f) => GetDocRowRep (D1 d f) where
  getDocRowRep _ = MyRowRepresentation
    (datatypeName @d undefined)
    (getDocRowCon (Proxy @f))

class GetDocRowCon f where
  getDocRowCon :: Proxy f -> String

instance (Selector s, Typeable a) => GetDocRowCon (C1 c (S1 s (Rec0 a))) where
  getDocRowCon _ = show $ typeRep (Proxy @a)

-- newtype派生Generic即可
newtype MyType0 = MyType0 Int16 deriving (Generic)
newtype MyType1 = MyType1 Int8 deriving (Generic)
newtype MyType2 = MyType2 Int32 deriving (Generic)
newtype MyType3 = MyType3 Word8 deriving (Generic)

main :: IO ()
main = do
  let table = [
        toDocRow (Proxy :: Proxy MyType0),
        toDocRow (Proxy :: Proxy MyType1),
        toDocRow (Proxy :: Proxy MyType2),
        toDocRow (Proxy :: Proxy MyType3)
      ]
  print table

两种方案都可以满足你的需求,生成对应的结构后你可以自行拼接为markdown表格写入文件即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 20:45:02