2016-12-05 7 views
4

Я строю eDSL поверх HaTeX. Проблема, с которой я сталкиваюсь, заключается в том, что я хочу отображать выражения Haskell в моем документе LaTeX, и я хочу использовать одно и то же выражение Haskell, чтобы помочь сгенерировать документ.Как вызвать квазикватер для синтаксиса haskell явно?

Очевидным ответом является копирование и вставка выражения так, чтобы оно отображалось как в кавычках, так и в реальном времени. Я хочу избежать этого, потому что выражение может быть изменено.

То, что я представляю, представляет собой квазицикл, который соединяет его содержимое по мере его появления и выводит строку, которая представляет его.

К примеру, вот что я хотел бы ввести:

document = do 
    title "this is an example document" 
    paragraph "This is normal text. We will now show the Haskell code that generates a table" 
    [quoted| makeTable ["heading1","heading2"] ["cell1","cell2"] |] 

, и я хотел бы квази цитату расширить до:

document = do 
    title "this is an example document" 
    paragraph "This is normal text. We will now show the Haskell code that generates a table" 
    makeTable ["heading1","heading2"] ["cell1","cell2"] 
    listing Haskell "makeTable [\"heading1\",\"heading2\"] [\"cell1\",\"cell2\"]" 

Для этого мне нужно написать QuasiQuoter:

quoted :: QuasiQuoter 
quoted = QuasiQuoter 
    { quoteExp = \str -> [e| $(_ str) >> listing Haskell $(lift str) |] } 

Я не уверен, что заменить дырку в $(_ str). Мне нужно заменить его выражением квазициклов выражения Haskell, но я не уверен, как его назвать. Если e был e :: QuasiQuoter, я мог бы заполнить отверстие $(quoteExp e str), но он, к сожалению, не работает. Что мне следует заполнить?

ответ

5

Короткий ответ: нет простого способа. This question по-прежнемубыл без ответа по причине. String -> Q Exp для Haskell жестко. Лучшим способом, вероятно, является haskell-src-meta, который предоставляет парсеры, которые возвращают шаблон Haskell AST. В частности, модуль Language.Haskell.Meta.Parse дает нам parseExp :: String -> Either String Exp.

import Language.Haskell.Meta.Parse (parseExp) 

quoted :: QuasiQuoter 
quoted = QuasiQuoter 
    { quoteExp = \str -> 
     case parseExp str of 
      Left msg -> fail "Could not parse expression." 
      Right exp -> [e| $(pure exp) >> listing Haskell $(liftString str) |] } 
+0

Это круто, спасибо! Кажется, это работает замечательно. Я предположил, что parseExp не находится в монаде Q, что он может плохо обрабатывать области, но это так. Информация о пакете не является конкретной информацией о том, чего не хватает. Вы знаете больше об этом? – simon1505475

+1

@ simon1505475 Да, этот пакет нуждается в некоторой любви. Под капотом он опирается на 'haskell-src-exts', который дает вам возможность указать' ParseMode'. 'haskell-src-meta', вероятно, использует [' defaultParseMode'] (https://hackage.haskell.org/package/haskell-src-exts-1.19.0/docs/Language-Haskell-Exts-Parser.html#v : defaultParseMode), в этом случае «По умолчанию это неизвестное имя файла, никакие расширения (например, Haskell 98), не игнорируют прагмы LANGUAGE, игнорируют прагмы LINE и не забывают о проблемах с прелюдией». – Alec

+1

@ simon1505475 Я возвращаю свой предыдущий комментарий. [Используется режим разбора] (https://github.com/bmillwood/haskell-src-meta/blob/master/src/Language/Haskell/Meta/Parse.hs#L70-L79) – Alec