Нелинейные шаблоны в квази-кавычках

Я следовал этому руководству, чтобы реализовать квази-цитируемый 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 |] в паттерн Хаскелла (Add a ((== a) -> True)),

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

0 ответов

Другие вопросы по тегам