2013-05-07 35 views
4

给定一个Haskell表达式,我想执行alpha转换,即。重命名一些非自由变量。Haskell表达式上的Alpha转换

我已经开始实现我自己的这个功能,它在haskell-src-exts Exp树上工作,但事实证明这是令人惊讶的不平凡,所以我不禁想知道 - 是否有一个既定的easy-这种类型的源转换可用的库解决方案吗?理想情况下,它应该与haskell-src-exts集成。

+0

您可能会发现ekmett的[bound](https://github.com/ekmett/bound/)库有帮助 – 2013-09-21 18:00:51

回答

5

这是“Scrap Your Boilerplate”样式泛型库闪耀的问题之一!

我最熟悉的一个是the uniplate package,但目前我没有安装它,所以我将使用the lens package中的(非常相似)功能。这里的想法是,它使用Data.Data.Data(这是有史以来最合适的名字)和相关类以多态方式执行泛型操作。

这里有一个最简单的例子:

alphaConvert :: Module -> Module 
alphaConvert = template %~ changeName 

changeName :: Name -> Name 
changeName (Ident n) = Ident $ n ++ "_conv" 
changeName n = n 

(%~)运营商与lens,只是手段,以功能changeName适用于一般的穿越template选择一切。因此,它会查找每个字母数字标识符并将其附加到_conv。因为它不本地绑定和那些在外侧范围内定义(如被导入)标识符区分

module AlphaConv where 
import Language.Haskell.Exts 
import Control.Lens 
import Control.Lens.Plated 
import Data.Data.Lens 

instance Plated_conv Module_conv 
main_conv 
    = do ParseOk_conv md_conv <- parseFile_conv "AlphaConv.hs" 
     putStrLn_conv $ prettyPrint_conv md_conv 
     let md'_conv = alphaConvert_conv md_conv 
     putStrLn_conv $ prettyPrint_conv md'_conv 

alphaConvert_conv :: Module_conv -> Module_conv 
alphaConvert_conv = template_conv %~ changeName_conv 

changeName_conv :: Name_conv -> Name_conv 
changeName_conv (Ident_conv n_conv) 
    = Ident_conv $ n_conv ++ "_conv" 
changeName_conv n_conv = n_conv 

不是非常有用的,但它说明的基本思想:在运行上其自己的源此程序产生这。

lens看起来有点吓人(它有更多的功能比这更多);你可能会发现uniplate或其他图书馆更平易近人。

您接近实际问题的方式将是多部分转换,首先选择要在其中进行阿尔法转换的子表达式,然后使用这些转换来修改要更改的名称。

+2

泛型解决了一个可能的问题(使用AST)而不是另一个问题(确定alpha等价,capture-避免等)。我把这个问题解释为更多关于后者的问题,这里有一些库('unbound','bound'),但我不知道它们是否可以很容易地应用到'haskell-src-exts'。 – 2013-05-08 01:05:02

+0

+1,但是,我不确定这是我在找什么。我不熟悉你提到的库,但我真正想避免的不是那么多的样板,而是真正的逻辑(大多数情况下确定绑定名称和自由名称)。 – xcvii 2013-05-08 07:49:49