Выделение внутри квазицикла в шаблоне Haskell
Я пытаюсь ознакомиться с Template Haskell, и, к моему удивлению, код ниже компилируется под ghc
(версия 6.10.4).
main = do
let
y = [| "hello" + 1 |]
putStr ""
Это говорит мне о том, что в квазициклах нет никакой проверки. Это не то, что я ожидал после прочтения оригинального paper в Template Haskell. Кроме того, следующая программа не компилируется.
main = do
let
y = [| "hello" && True |]
putStr ""
Что здесь происходит?
Ответы
Ответ 1
Похоже, что GHC делает тип, проверяя все цитаты , но предполагает, что все сгенерированные ограничения экземпляра могут быть удовлетворены.
В этом коде:
main = do
let
y = [| "hello" + 1 |]
putStr ""
Кран y подлежит типу в предположении, что мы имеем экземпляр Num String. Поскольку GHC не может точно сказать, что вы не представите такой экземпляр до того, как будет сражаться, тогда он не даст ошибку типа.
В этом коде:
main = do
let
y = [| "hello" && True |]
putStr ""
Нет никакого способа, чтобы y можно было успешно спланировать успешно, независимо от того, какую среду среды вы настроили.
Это всего лишь один пример того, как механизм проверки шаблонов Template Haskell слишком мягкий. Дальнейшие примеры обсуждаются в блоге Саймона PJ в http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposal, где он предлагает изменение типа не проверяет любые цитаты вообще.
Ответ 2
Шаблон Haskell имеет две основные операции:
- Подъем:
[| |]
- сращивание
$( )
Когда вы обертываете что-то в скобках в Оксфорде, вы задерживаете его проверку типа (и оценку) и вместо этого создаете фрагмент AST, который будет проверяться по типу, когда он снова сращивается.
АСТ, который построен, можно наблюдать:
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
main = print =<< runQ [| "hello" + 1 |]
Запуск этой программы (или ввод выражения скобки в GHCi), и мы получим хорошо сформированный АСТ, но тот, который не является корректным, если рассматривать его как фрагмент Haskell:
InfixE (Just (LitE (StringL "hello" ))) (VarE GHC.Num. +) (Just (LitE (IntegerL 1)))
Теперь, когда мы пытаемся связать его, введите проверку:
*Main> :t [| "hello" + 1 |]
[| "hello" + 1 |] :: Q Exp
*Main> $( [| "hello" + 1 |] )
<interactive>:1:4:
No instance for (Num [Char])
arising from the literal `1'
Как и ожидалось. Итак, да, выражения TH проверяются по типу, но в конце концов, когда они снова подключены к программе.