Haskell中的AST转换

时间:2015-01-30 08:30:56

标签: haskell

我有一个AST,其根节​​点的类型为E.Root。我需要将其转换为具有类型为I.Root的根节点的AST。

我现在可以定义一个带有类型签名的函数eToI

eToI :: E.Root -> AdditionalInfo -> I.Root

但是,两个AST共享很多节点。因此,函数eToF有很多样板代码构建来自I's节点的E's个节点,这些节点本质上是相同的。

我想解决这两个问题:

  1. 在类型级别,避免定义I的节点。我有所有的节点 E定义的。我在I中定义了哪些节点发生了变化。我可以吗? 编译器通过某种方式映射什么来生成I中的所有类型 需要改变?

  2. 在价值级别,我只想为其定义转换     变化的节点(假设E的A映射到I的Z ..):

        aToZ :: E.A -> AdditionalInfo -> I.Z
        bToY :: E.B -> AdditionalInfo -> I.Y
    

    现在,编译器可以生成像eToI这样的函数吗?

        eToI :: E.Root -> AdditionalInfo -> I.Root
    
  3. Haskell的惯用方法是什么?

1 个答案:

答案 0 :(得分:2)

有时,您可以将E.RootI.Root的常见方面分解为一种或多种可重用的数据类型。它通常也有助于将AdditionalInfo -> ...隐藏在monad或applicative functor中。例如,这里有一些伪代码:

module Common where
  {-# LANGUAGE DeriveTraversable #-}
  data Reusable root = ... root ...
    deriving (Functor, Foldable, Traversable)

module E where
  import Common
  data Root = Leaf (Reusable Root) | Node Root

module I where
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  import Common

  import Data.Monoid

  data Root = Root [Reusable Root]
    deriving Monoid

module Transform where
  import Common
  import qualified E
  import qualified I

  import Control.Applicative
  import Control.Monad.Reader
  import Data.Monoid

  type AdditionalInput = ...
  type F = Reader AdditionalInput

  convertRoot :: E.Root -> F I.Root
  convertRoot (Leaf reusable) =
    traverse convertRoot reusable
  convertRoot (Node left right) =
    liftA2 mappend (convertRoot left) (convertRoot right)

现在我可以使用traverseReusable E.RootReusable I.Root之间进行转换。