在模板Haskell中的准引号里面的Typechecking

时间:2011-03-19 23:45:43

标签: haskell types metaprogramming type-systems

我正在努力熟悉Template Haskell,令我惊讶的是,下面的代码在ghc(版本6.10.4)下编译。


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

这告诉我,准引号内没有类型检查。这不是我在阅读Template Haskell上的原始paper后所期望的。此外,以下程序无法编译。


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

这里发生了什么?

2 个答案:

答案 0 :(得分:15)

看起来GHC确实键入了所有引用,但假设可以满足所有生成的实例约束。

在此代码中:

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

假设我们有一个Num String实例,y括号是可输入的。由于GHC无法确定在拼接y之前不会引入这样的实例,因此不会出现类型错误。

在此代码中:

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

无论您设置何种实例环境,都无法成功拼接y。

这只是模板Haskell的类型检查机制过于宽松的一个例子 - 另外的例子在Simon PJ在http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposal的博客文章中进行了讨论,在那里他提出了一个改变,即不打算检查任何引用。< / p>

答案 1 :(得分:12)

模板Haskell有两个主要操作:

  • 解除:[| |]
  • 拼接$( )

当你在牛津括号中包装东西时,你会延迟它的类型检查(和评估),而是构建一个AST片段,当它被拼接回来时将进行类型检查。

可以观察到构建的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表达式是类型检查的,但是在最后一点,当拼接回程序时。