这段代码编译得很好:
data None = None { _f :: Int }
type Simpl = Env
type Env = Int但是,这段代码出现了一个错误:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data None = None { _f :: Int }
type Simpl = Env
makeLenses ''None
type Env = Int错误:
Not in scope: type constructor or class `Env'我只是在类型声明之间添加了一行makeLenses ''None。
这意味着TemplateHaskell代码可以更改类型构造函数的范围?
有没有人知道这个问题的细节(或者如何避免这个问题)?
发布于 2014-01-02 05:44:37
如果按照以下方式重新排序代码,它会工作:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data None = None { _f :: Int }
type Simpl = Env
type Env = Int
makeLenses ''None当您使用模板Haskell剪接将新的顶级声明添加到您的代码中时,正如makeLenses所做的那样,代码中声明的顺序突然变得重要了!
原因是,通常编译Haskell程序需要首先收集所有顶级声明,然后在内部重新排序,以便将它们按依赖关系排序,然后逐个编译它们(或者对相互递归的声明逐组编译)。
通过运行任意代码引入新的声明,因为GHC不知道makeLenses可能需要运行哪些声明,也不知道它将生成哪些新的声明。因此,它不能将整个文件按依赖关系排序,而只是某种程度上放弃,希望用户自己去做,至少在决定声明应该在连接之前还是之后进行。
我在网上唯一能找到的解释这一点的参考资料是在原始模板Haskell纸第7.2节中,其中说算法是:
[d1,...,da]
splice ea
[da+2,...,db]
splice eb
...
splice ez
[dz+2,...,dN]其中唯一的剪接声明是显式指示的,因此每个组
[d1,...,da]等都是普通的Haskell声明。
所以这里的问题是,剪接之前的第一组声明是分开处理的,第二组是剪接后的第二组,它看不到Env的定义。
我的一般经验是,如果可能的话,把这样的剪接放在文件的底部,但我不认为这样的剪接永远都能工作。
https://stackoverflow.com/questions/20876147
复制相似问题