Шаблон Haskell: ошибка этапа

Я пытаюсь понять, как Quasi Quoter генерирует структуры TH. Итак, я пытаюсь преобразовать первый пример из Метапрограммирование шаблонов для Haskell, от формата в кавычках к просто типам.

gen :: [Format] -> ExpQ -> ExpQ
gen []       x = x
gen (D:xs)   x = [| \n -> $(gen xs [| $x ++ show n |]) |]
gen (S:xs)   x = [| \s -> $(gen xs [| $x ++ s |]) |]
gen (L s:xs) x = gen xs [| $x ++ $(THS.lift s) |]

gen (D:xs) x превратится в

gen (D:xs)  x = lamE [varP $ mkName "n"]
                    (appE (appE (varE 'gen) (varE 'xs))
                        (uInfixE (x) (varE '(Prelude.++))
                            (appE (varE 'Prelude.show) (varE $ mkName "n"))))

Однако этот фрагмент не будет компилировать ссылку на 'xs.

GHC выдает следующую ошибку:

src/Print/Default.hs:28:51:
    Stage error: the non-top-level quoted name 'xs
    must be used at the same stage at which is is bound
    In the Template Haskell quotation 'xs
    In the first argument of `varE', namely 'xs
    In the second argument of `appE', namely `(varE 'xs)'

Есть ли какой-то другой способ, которым вам нужно сослаться на имя параметра функции, чтобы Template Haskell мог его использовать?


person Andrew Rademacher    schedule 02.06.2014    source источник
comment
Это преобразование не является правильным. Обратите внимание, что в первой версии локально привязанные имена, которые заключены в кавычки, также соединяются обратно. Так что, если x локально связано, у вас не может быть $x, но вы можете иметь [| ... $x ... |]. Во 2-й версии вы этого не сделали, да и делать это не имеет смысла, так как lamE [varP ..] ожидает ExpQ, а \n -> внутри стыка ожидает String.   -  person user2407038    schedule 03.06.2014


Ответы (1)


user2407038 прав что перевод выключен. Вот более правильный перевод:

    gen (D:xs)   x = lamE [varP (mkName "n")] $
                        gen xs $
                              varE '(++)
                                    `appE` x
                                    `appE` (varE 'show `appE` varE (mkName "n"))

Вы не ссылаетесь на имя xs или gen здесь: вы просто рекурсивно вызываете функцию, чтобы сгенерировать немного больше AST. Это держит все в той же стадии.

person aavogt    schedule 02.06.2014