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

如何通过泛型编程获取值内部所有TypeRep?已实现方案存问题

Absolutely! You can build this typeReps function using Haskell's generic programming tools from the Data.Data library. Let's break down the issues in your current code and walk through correct implementations that meet your requirements.

Issues in Your Current Code

Your implementation has two critical problems causing duplicate TypeReps and incorrect constructor handling:

  1. Misusing the input value in fcstr:
    Your fcstr function uses typeOf a (the type of the entire input) instead of the type associated with the constructor g being processed. This leads to duplicate root-type entries every time a constructor (like the empty list [] in ['a']) is handled.
  2. Ignoring the constructor parameter:
    You don't use the g parameter in fcstr, and since g isn't constrained to Typeable, you can't get its actual type. This defeats the purpose of gfoldl, which passes constructors to fcstr to initialize the folding process.

Correct Implementations

The core goal is to collect the TypeRep of the root value, then recursively gather types from all direct and indirect sub-values. Here are two approaches:

First, Define Your Wrapper Type

Let's start with a proper definition for your TypeReps wrapper (and a helper for concatenation):

{-# LANGUAGE DeriveDataTypeable #-}
module Example where
import Data.Data
import Data.Typeable
import Data.List (nub) -- For optional deduplication

newtype TypeReps a = TypeReps { getTypes :: [TypeRep] } deriving Show

(<++>) :: TypeReps (d -> b) -> TypeReps d -> TypeReps b
(<++>) (TypeReps xs) (TypeReps ys) = TypeReps (xs ++ ys)

Option 1: Preserve All Nested Types (Including Duplicates)

This implementation strictly follows the recursive structure of your data, including types from nested constructors like empty lists:

typeReps :: (Data a) => a -> TypeReps a
typeReps x = TypeReps $ typeOf x : concatMap (getTypes . typeReps) (gmapQ id x)

Testing this matches your first example perfectly:

>>> typeReps (1 :: Int, 'a')
TypeReps {getTypes = [(Int,Char),Int,Char]}
>>> typeReps ['a']
TypeReps {getTypes = [[Char],Char,[Char]]} -- Includes empty list's [Char] type

Option 2: Deduplicate Types

If you want to remove duplicate TypeReps (like the extra [Char] from the empty list), use nub to filter duplicates:

typeReps :: (Data a) => a -> TypeReps a
typeReps x = TypeReps . nub $ typeOf x : concatMap (getTypes . typeReps) (gmapQ id x)

This gives you the clean output you showed for your Foo example:

>>> data Foo = Foo [Char] deriving (Data, Typeable, Show)
>>> typeReps (Foo ['a', 'b'])
TypeReps {getTypes = [Foo,[Char],Char]}

Option 3: Corrected gfoldl Approach

If you prefer to stick with gfoldl (as in your original code), here's a fixed version that uses constructors correctly:

typeReps :: (Data a) => a -> TypeReps a
typeReps x = gfoldl step (\_ -> TypeReps [typeOf x]) x
  where
    step :: forall d b. Data d => TypeReps (d -> b) -> d -> TypeReps b
    step (TypeReps acc) d = TypeReps $ acc ++ getTypes (typeReps d)

Here, fcstr initializes the fold with the root type once, and step recursively adds types from each sub-value to the accumulator.

Why This Works

  • gmapQ id x extracts all direct sub-values of x (e.g., the two elements of a tuple, the list inside a Foo constructor).
  • Recursively calling typeReps on each sub-value captures nested types down to the deepest elements.
  • Concatenating these lists gives a flat sequence of all types from the root to the leaves of your data structure.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:49:07