Проверка типов внутри квази-кавычек в шаблоне Haskell - PullRequest
20 голосов
/ 20 марта 2011

Я пытаюсь ознакомиться с шаблоном Haskell , и, к моему удивлению, приведенный ниже код компилируется в ghc (версия 6.10.4).


    main = do
       let
           y = [| "hello" + 1 |]
       putStr ""

Это предложениедля меня, что нет проверки типов внутри квази-кавычек.Это не то, что я ожидал после прочтения оригинальной бумаги на Template Haskell.Более того, следующая программа не компилируется.


    main = do
       let
          y = [| "hello" && True |]
       putStr ""

Что здесь происходит?

Ответы [ 2 ]

15 голосов
/ 20 марта 2011

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

В этом коде:

main = do
   let
       y = [| "hello" + 1 |]
   putStr ""

Скобка y может быть набрана при условии, что у нас есть экземпляр Num String. Поскольку GHC не может с уверенностью сказать, что вы не представите такой экземпляр до вложения y, это не приводит к ошибке типа.

В этом коде:

 main = do
   let
      y = [| "hello" && True |]
   putStr ""

Невозможно успешно соединить y, независимо от того, какую среду экземпляра вы настроили.

Это всего лишь один пример того, как механизм проверки типов в Template Haskell слишком мягок - дополнительные примеры обсуждаются в блоге Саймона ПиДжея по адресу http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposal,, где он предлагает изменить проверку типов без каких-либо цитат вообще.

12 голосов
/ 20 марта 2011

Шаблон Haskell имеет две основные операции:

  • подъем: [| |]
  • сращивание $( )

Когда вы заключаете что-то в скобки Оксфорда, вы задерживаете проверку (и оценку) его типа и вместо этого создаете фрагмент AST, который будет проверен на тип, когда он будет вставлен обратно.

АСТ, который построен, можно наблюдать:

{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
main = print =<< runQ  [| "hello" + 1 |]

Запуск этой программы (или ввод выражения в скобках в GHCi), и мы получаем правильно сформированный AST, но тот, который не является корректным по типу, если рассматривается как фрагмент 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 проверяются типом, но в более поздний момент, когда они вставляются обратно в программу.

...