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表达式是类型检查的,但是在最后一点,当拼接回程序时.