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

Mar*_*ger 20 haskell types type-systems metaprogramming

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


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

这告诉我,准引号内没有类型检查.在阅读关于Template Haskell 的原始论文后,这不是我所期望的.而且以下程序不编译.


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

这里发生了什么?

Max*_*oke 15

看起来GHC会对所有引用进行类型检查,假设可以满足所有生成的实例约束.

在这段代码中:

main = do
   let
       y = [| "hello" + 1 |]
   putStr ""
Run Code Online (Sandbox Code Playgroud)

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

在这段代码中:

 main = do
   let
      y = [| "hello" && True |]
   putStr ""
Run Code Online (Sandbox Code Playgroud)

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

这是模板Haskell的类型检查机制是怎样过于宽松只是一个例子-进一步的例子在西蒙PJ的博客文章在讨论http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposal,他在那里提议更改为不打印任何报价.


Don*_*art 12

模板Haskell有两个主要操作:

  • 吊装: [| |]
  • 接片 $( )

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

可以观察到构建的AST:

{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
main = print =<< runQ  [| "hello" + 1 |]
Run Code Online (Sandbox Code Playgroud)

运行这个程序(或在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'
Run Code Online (Sandbox Code Playgroud)

正如我们所料.所以,是的,TH表达式是类型检查的,但是在最后一点,当拼接回程序时.

  • 谢谢唐.我仍然不明白的是为什么[|"你好"+1 |]类型检查,但是[|"hello"&& 1 |]没有(即使没有被拼接).最初的Sheard,Peyton Jones论文在第66页说:"类型检查术语e立即检测到任何内部类型不一致;例如,[|'a'+ True |]将立即被拒绝". (2认同)