Шаблон Haskell: есть ли функция (или специальный синтаксис), которая анализирует строку и возвращает Q Exp?
Я пытаюсь немного узнать о шаблонах Haskell и Quasi Quotation, и я ищу функцию, которая принимает String
и анализирует это Q Exp
, так что тип:
String -> Q Exp
Попытка поиска в Google, но результаты, которые я видел, были связаны с подъемом строковых литералов в Q Exp
и самый близкий был Language.Haskell.TH.dyn
который делает то, что я хочу, но только для одной переменной.
Есть ли другие варианты? Например, специальный синтаксис? Я просто в процессе ознакомления с [||]
а также $()
так что, может быть, есть что-то для этого тоже?
Пример того, как я представляю, как это будет работать:
runQ (parse "(1+)") == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing
Кроме того, я знаю об этом
runQ [| (1+) |] == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing
но это не будет работать с переменными строками, потому что - понятно - строка внутри воспринимается как литерал.
runQ [| "(1+)" |] == LitE (StringL "(1+)")
Изменить (2015-07-25): я начал использовать haskell-src-meta
и, похоже, до сих пор хорошо работает. Однако это займет совсем немного времени, чтобы cabal install
(около 10 минут на моей машине). Что обидно, мой пакет на самом деле довольно маленький, и я хотел бы, чтобы установка могла быть быстрой. Кто-нибудь знает решение, которое имеет меньшие зависимости?
1 ответ
Как все уже сказали haskell-src-meta
обеспечивает
parsePat :: String -> Either String Pat
parseExp :: String -> Either String Exp
parseType :: String -> Either String Type
parseDecs :: String -> Either String [Dec]
где Pat
, Exp
, Type
, а также Dec
такие же как из Language.Haskell.TH.Syntax
,
Почему GHC не предоставляет свой собственный парсер?
Оно делает. Запустите GHCi с ghci -package ghc
(ghc
это скрытый пакет по умолчанию), и вы можете импортировать Parser
, Имеет функции для разбора String
в предварительные ASTs (чьи декларации данных находятся в HsSyn
) для шаблонов, выражений, типов и объявлений.
Хорошо, тогда почему не существует библиотеки, которая использует этот синтаксический анализатор и преобразует свои выходные данные в AST из
template-haskell
(тот, вLanguage.Haskell.TH.Syntax
)?
Заглядывать внутрь HsSyn
очевидно, что AST не совсем такой же, как в Language.Haskell.TH.Syntax
, Откройте оба HsExpr
а также Exp
и бок о бок вы увидите, что последний заполнен такими типами, как PostTc id <some-other-type>
а также PostRn id <some-other-type>
, По мере того, как AST передается от парсера к переименователю в средство проверки типов, все эти биты и кусочки медленно заполняются. Например, мы даже не знаем, как работают операторы, пока не перейдем к проверке типов!
Чтобы сделать нужные нам функции, нам нужно было бы запустить гораздо больше, чем просто анализатор (по крайней мере, также переименователь и средство проверки типов, а может и больше). Представьте себе: каждый раз, когда вы хотите разобрать даже маленькое выражение, например "1 + 2"
вам все равно придется печатать кучу импорта. Даже тогда, возвращаясь к Language.Haskell.TH.Syntax
не будет прогулкой в парке: у GHC есть множество особенностей, таких как собственный особый глобальный способ хранения имен и идентификаторов.
Хммм... но что GHC делает с квази-кавычками?
Это классная часть! В отличие от Exp
, HsExpr
имеет HsSplice
для представления соединений. Посмотрите на типы для первых двух конструкторов:
HsTypedSplice :: id -> LHsExpr id -> HsSplice id. -- things like [|| 1 + 2 ||]
HsUntypedSplice :: id -> LHsExpr id -> HsSplice id -- things like [| 1 + 2 |]
Обратите внимание, что они не хранят String
они уже хранят AST! Соединения анализируются одновременно с остальной частью AST. И точно так же, как и остальная часть AST, сращивания будут переданы переименователю, средству проверки типов и т. Д., Где будет заполнена недостающая информация.
Так что принципиально невозможно использовать парсер GHC
Возможно нет. Но вытащить его из остальной части GHC может быть довольно сложно. Если для использования парсера GHC нам нужно также запустить средство проверки типов и переименовывать, может быть более элегантно и просто просто использовать автономный парсер, такой как haskell-src-exts
(который является то, что Haskell-src-meta
зависит от), который может делать все за один проход (например, исправления - это одна из вещей, которую вы должны заранее предоставить этому анализатору).