准引号中的非线性模式

时间:2018-02-22 16:07:23

标签: haskell pattern-matching template-haskell quasiquotes

我跟着this tutorial实现了一个准引用的DSL,现在我想以引用的模式支持non-linear patterns。这将允许模式中重复的绑定器断言匹配数据的相等性。例如,可以编写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是否在范围内。如果没有,那么只需创建一个具有相同名称的活页夹。否则,创建一个view pattern (== s) -> True,声明匹配的数据等于已绑定到s的数据。基本上,我想将引用的模式[expr| $a + $a |]转换为Haskell模式(Add a ((== a) -> True))

但那没用。生成的Haskell模式为Add a a,这意味着lookupValueName永远不会认为a在范围内。我误解了lookupValueName的工作原理吗?或者是否有更好的方法来实现非线性模式?

如果您想使用它,则完整代码为here。简而言之,我正在制作一个准引号以匹配Java源代码。

更新1:

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

更新2:

所以我咬了一下子弹并用范围内的monad编写了范围内的名称,然后使用transformM遍历解析树,用{{{}替换每个范围内的元变量x。 1}}:

((== 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 从头到底遍历树,因此可以首先将内部元变量添加到集合中。

0 个答案:

没有答案