我需要对AST进行转换;下面是AST的一部分:
data Expr
= BinExpr { beOp :: BinaryOp
, beLeft :: Expr
, beRight :: Expr }
| Name Text
| IntegerLit Integer
| StringLit Text
deriving (Data, Typeable)这是一个相当复杂的AST,所以涉及很多类型。
我使用合金生成泛型转换,特别是:
autoGen :: IO ()
autoGen = do
createDirectoryIfMissing True baseDir
writeInstancesTo inst doc imports targetFile
where
inst = allInstances GenWithoutOverlapped
doc = [genInstance (undefined :: Doc)]
imports = header ++ instanceImports现在,这在使用String时很好,但我正在尝试迁移到Data.Text。当代码生成运行时,它将读取Data.Text的内部内容,如下所示:
instance (Alloy ([(GHC.Types.Char)]) (f :- ops) BaseOp) =>
Alloy ((Data.Text.Internal.Text)) BaseOp (f :- ops) where
transform _ ops (Data.Text.Internal.pack a0)
= Data.Text.Internal.pack
(transform ops BaseOp (a0))我相信pack与GHC内部元素有关联,所以这不是一个有效的模式匹配,而且不管怎么说,让代码与Data.Text的内部元素混在一起很容易破坏不变量。(编辑:看起来有一个instance Data Text where gfoldl f z txt = z packf(unpack txt)声明,但无论如何,我不需要/希望遍历文本值。)
有没有办法强迫合金把一种类型当作原子呢?我希望避免使用newtype来包装文本,因为所有处理as的代码都需要处理它,这与使用泛型来避免样板的目的不同。
发布于 2018-06-11 11:24:02
也许可以试试这个技巧:我们将Expr类型参数化,以便在用合金派生实例时覆盖用于Text的Data实例。
data Expr_ text
= BinExpr { beOp :: BinaryOp
, beLeft :: Expr_ text
, beRight :: Expr_ text }
| Name text
...
| StringLit text代码库的其余部分可以使用这个同义词,希望不会过多地解决类型推断问题。
type Expr = Expr_ Text但是对于Data-generic操作,我们在Text周围使用一个newtype包装器,并使其行为像一个髓构造函数,希望合金不需要gunfold的结果(或者您可以使用模式同义词使其表现为字符串)。
newtype DataText = DataText Text
instance Data DataText where
gunfold _ f _ = f undefined
...然后,autoGen将专门处理DummyText的所有内容。
使用Data.Coerce.coerce可以方便地在Expr_ DataText和Expr上的函数之间进行转换。
coerce :: Expr_ DataText -> Expr
coerce :: Expr -> Expr_ DataText
coerce :: (Expr_ DataText -> Expr_ DataText) -> Expr -> Expr这可能用于根据从您派生的实例为Expr编写合金类型类的实例。它有点样板,但希望它能够被包含和隐藏,而不会影响代码的其余部分。
https://stackoverflow.com/questions/50790121
复制相似问题