3

我按照本教程实现了一个准引用 DSL,现在我想在引用模式中支持非线性模式。这将允许模式中的重复绑定器断言匹配数据的相等性。例如,然后可以编写eval [expr| $a + $a|] = 2 * eval a. 我修改antiExprPat如下:

antiExpPat (MetaExp s) = 
  Just (do b <- lookupValueName s
           let n = mkName s
               p0 = VarP n
               p1 <- (viewP [|(== $(varE n))|] [p|True|])
           let res = case b of Nothing -> p0
                               _ -> p1
           return res)
antiExpPat _ = Nothing

这个想法是用来lookupValueName检查反引号名称s是否在范围内。如果没有,那么只需创建一个具有相同名称的活页夹。否则,创建一个视图模式 (== s) -> True,断言匹配的数据等于已经绑定到的数据s。本质上,我想将引用的模式转换[expr| $a + $a |]为 Haskell 模式(Add a ((== a) -> True))

但这没有用。生成的 Haskell 模式是Add a a,这意味着lookupValueName从不认为a在范围内。我误解了它的lookupValueName工作原理吗?还是有更好的方法在这里实现非线性模式?

如果你想玩它,完整的代码在这里。简而言之,我正在制作一个准引用器以匹配 Java 源代码。


更新1:

正如@chi 指出的那样,lookupValueName只检查拼接的上下文,而我需要检查拼接的内容。知道如何进行吗?


更新 2:

所以我咬紧牙关,用一个状态单子串接了一组范围内的名称,并遍历了解析树,用它替换了每个范围内的transformM元变量:x((== x) -> True)

dataToPatQ (const Nothing `extQ` ...) (evalState (rename s) DS.empty)
...
rename :: Language.Java.Syntax.Stmt -> State (DS.Set String) Language.Java.Syntax.Stmt
rename p = transformM rnvar p
  where rnvar (MetaStmt n) = do s <- get
                                let res = if DS.member n s 
                                          then (SAssertEq n) 
                                          else (MetaStmt n)
                                put (DS.insert n s)
                                return res
        rnvar x = return x

它在我的输入上得到了正确的结果,但我不知道它是否正确,特别是考虑transformM到自下而上遍历树,因此可以首先将内部元变量添加到集合中。

4

0 回答 0