根据您的后续问题,泛型库似乎比 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
:必须有Typeable
fora
和Data
for 的实例t a
。在您的情况下t a
是Expr a
,这意味着您需要将 a 添加deriving Data
到 的定义中,并且在您使用的任何内容的范围内Expr
都有一个Data
实例。a