Нелинейные паттерны в квазикотировках

Я выполнил это руководство, чтобы реализовать 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 пересекает дерево снизу вверх, поэтому сначала в набор могут быть добавлены внутренние метапеременные.


person rem    schedule 22.02.2018    source источник
comment
Я думаю, что lookupValueName рассматривает переменные в области видимости только вне соединения, а не те, которые определяются в шаблоне. Например. eval (Add x [expr| ... |]) = ... может видеть x. Вам придется самостоятельно найти переменные, определенные внутри фрагмента шаблона.   -  person chi    schedule 22.02.2018