首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Haskell:模板Haskell和范围

Haskell:模板Haskell和范围
EN

Stack Overflow用户
提问于 2014-01-02 04:03:40
回答 1查看 1.4K关注 0票数 14

这段代码编译得很好:

代码语言:javascript
复制
data None = None { _f :: Int }
type Simpl = Env

type Env = Int

但是,这段代码出现了一个错误:

代码语言:javascript
复制
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens

data None = None { _f :: Int }

type Simpl = Env

makeLenses ''None

type Env = Int

错误:

代码语言:javascript
复制
Not in scope: type constructor or class `Env'

我只是在类型声明之间添加了一行makeLenses ''None

这意味着TemplateHaskell代码可以更改类型构造函数的范围?

有没有人知道这个问题的细节(或者如何避免这个问题)?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-01-02 05:44:37

如果按照以下方式重新排序代码,它会工作:

代码语言:javascript
复制
{-# 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节中,其中说算法是:

  • 将声明分组如下:
代码语言:javascript
复制
[d1,...,da]
splice ea
[da+2,...,db]
splice eb
...
splice ez
[dz+2,...,dN]

其中唯一的剪接声明是显式指示的,因此每个组[d1,...,da]等都是普通的Haskell声明。

  • 对first组执行常规依赖项分析,然后进行类型检查。它的所有自由变量都应该在范围内。

所以这里的问题是,剪接之前的第一组声明是分开处理的,第二组是剪接后的第二组,它看不到Env的定义。

我的一般经验是,如果可能的话,把这样的剪接放在文件的底部,但我不认为这样的剪接永远都能工作。

票数 17
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20876147

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档