根据您的后续问题,泛型库似乎比 Functor 更适合您的情况。我建议只使用 SYB wiki 页面上提供的功能:
{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables, FlexibleContexts #-}
import Data.Generics
import Unsafe.Coerce
newtype C a = C a deriving (Data,Typeable)
fmapData :: forall t a b. (Typeable a, Data (t (C a)), Data (t a)) =>
(a -> b) -> t a -> t b
fmapData f input = uc . everywhere (mkT $ \(x::C a) -> uc (f (uc x)))
$ (uc input :: t (C a))
where uc = unsafeCoerce
额外类型的原因C是为了避免出现问题的极端情况,即出现与相同类型的字段a(有关 wiki 的更多详细信息)。的调用者fmapData不需要看到它。
与真正的函数相比,这个函数确实有一些额外的要求fmap:必须有Typeablefora和Datafor 的实例t a。在您的情况下t a是Expr a,这意味着您需要将 a 添加deriving Data到 的定义中,并且在您使用的任何内容的范围内Expr都有一个Data实例。a