3

所以,我有一个包含大量案例的 AST 数据类型,它由“注释”类型参数化

data Expr a = Plus a Int Int
    | ...
    | Times a Int Int

我有注释类型ST,还有一些功能f :: S -> T。我想在 Expr 值内使用我的转换将其Expr S转换为一个。Expr TfS

有没有办法使用 SYB 或泛型来做到这一点,并避免在每种情况下都进行模式匹配?这似乎是适合的事物类型。我只是对SYB不够熟悉,不知道具体的方法。

4

2 回答 2

6

听起来你想要一个Functor实例。这可以由 GHC 使用DeriveFunctor扩展自动派生。

于 2014-12-28T08:13:57.297 回答
2

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

于 2014-12-28T09:09:47.083 回答