在没有样板的情况下从类型“T a”转换为“T b”

时间:2014-12-28 06:01:01

标签: haskell ghc scrap-your-boilerplate ghc-generics

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

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

我有注释类型ST,还有一些函数f :: S -> T。我想使用Expr S并使用每个Expr T上的转化f将其转换为S,这转化为Expr值。

有没有办法使用SYB或泛型来做到这一点,并避免必须在每个案例上进行模式匹配?这似乎适合的类型。我对SYB不熟悉,知道具体的方法。

2 个答案:

答案 0 :(得分:6)

听起来你想要一个Functor实例。这可以通过GHC使用DeriveFunctor扩展名自动导出。

答案 1 :(得分:2)

根据您的后续问题,似乎一个泛型库比Functor更适合您的情况。我建议只使用SYB wiki page上给出的函数:

{-# 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必须有aData必须有t a 。在您的情况下,t aExpr a,这意味着您需要在deriving Data的定义中添加Expr,并拥有Data适用于您正在使用的a范围内的实例。