2014-12-28 57 views
3

所以,我有具有大量的情況下,這是由一種「註釋」類型從類型`T A`轉換爲`T B`而不樣板

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

我有參數的AST數據類型註釋類型ST,以及一些功能f :: S -> T。我想採用Expr S並將其轉換爲Expr T,使用我的轉換f對每個S發生在Expr值內。

有沒有辦法做到這一點使用SYB或泛型,並避免在每種情況下模式匹配?這似乎是這種適合的類型。我只是不熟悉SYB知道具體的做法。

+6

聽起來很像一個'Functor'。 'fmap'函數的類型爲'Functor f =>(a - > b) - >(f a - > f b)'。如果你說'Expr'是一個'Functor',那麼'fmap ::(a - > b) - >(Expr a - > Expr b)'。 – bheklilr

+5

如果您想避免編寫'Functor'定義的樣板文件,您可以使用'DeriveFunctor'擴展名。 –

+0

正是我在找的東西。把它寫成答案,我會接受它。謝謝! – jmite

回答

6

這聽起來像你想要一個Functor實例。這可以由GHC使用DeriveFunctor擴展自動導出。

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(更多細節有問題的極端情況維基)。 fmapData的來電者不需要看到它。

該功能確實有比較真實的fmap一些額外的要求:必須有Typeable實例爲a,並且Datat a。在你的情況下,t aExpr a,這意味着你需要添加一個deriving DataExpr的定義,以及Data範圍內的任何a你正在使用的範圍。

相關問題