【问题标题】:Is there a way to prevent Data.Generics.Alloy.GenInstances from scanning Data.Text.Internal?有没有办法阻止 Data.Generics.Alloy.GenInstances 扫描 Data.Text.Internal?
【发布时间】:2018-06-11 03:20:59
【问题描述】:

我需要对 AST 进行转换;这是 AST 的一部分:

data Expr
  = BinExpr { beOp    :: BinaryOp
            , beLeft  :: Expr
            , beRight :: Expr }
  | Name Text
  | IntegerLit Integer
  | StringLit Text
  deriving (Data, Typeable)

这是一个相当复杂的 AST,所以涉及的类型很多。

我正在使用alloy 来生成通用转换,具体来说:

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) 声明,但无论如何,我不需要/不想遍历 Text 值。)

有没有办法强制 Alloy 将类型视为原子类型?我希望避免使用新类型来包装 Text,因为所有使用 AST 的代码都需要处理它,这反而违背了使用泛型来避免样板的目的。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    不妨试试这个技巧:我们参数化 Expr 类型以在派生合金实例时覆盖用于 TextData 实例。

    data Expr_ text
      = BinExpr { beOp    :: BinaryOp
                , beLeft  :: Expr_ text
                , beRight :: Expr_ text }
      | Name text
      ...
      | StringLit text
    

    代码库的其余部分可以使用这个同义词,希望不会因为类型推断问题而破坏太多。

    type Expr = Expr_ Text
    

    但是对于 Data-generic 操作,我们使用 newtype 包装 Text 并使其表现得像一个空构造函数,希望合金不需要 gunfold 的结果(或者你可以它的行为类似于使用模式同义词的字符串)。

    newtype DataText = DataText Text
    
    instance Data DataText where
      gunfold _ f _ = f undefined
      ...
    

    autoGen 将在 DummyText 处专门处理所有内容。

    使用Data.Coerce.coerceExpr_ DataTextExpr 上的函数之间轻松转换。

    coerce :: Expr_ DataText -> Expr
    coerce :: Expr -> Expr_ DataText
    coerce :: (Expr_ DataText -> Expr_ DataText) -> Expr -> Expr
    

    这可能用于为Expr 编写合金类型类的实例,基于从您那里派生的实例。它有点样板,但希望它可以被包含和隐藏而不影响其余代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-28
      • 1970-01-01
      • 2019-10-20
      • 1970-01-01
      • 2020-02-29
      • 1970-01-01
      • 2020-05-04
      相关资源
      最近更新 更多