将.hs脚本加载到解释器中

时间:2012-01-25 01:12:51

标签: haskell ghci

在Haskell ghci,我试过

Prelude> :load filename.hs
Ok, modules loaded: Main.

遗憾的是,我无法运行文件中定义的任何功能。我编译了文件没有任何错误,但调用函数给出一个错误,“不在范围内:(函数名称)”。奇怪的是,一段时间之前,我没有遇到任何问题......

5 个答案:

答案 0 :(得分:3)

问题是您的编辑器正在使用类似

的代码编译代码
$ ghc foo.hs

由于你的文件没有模块声明,GHC假定模块被称为Main,因为你没有另外指定,因为它正在编译一个完整的程序,不会导出< / em> main以外的任何定义;也就是说,它就像你有一个模块声明一样:

module Main (main) where

GHCi默认为:

module Main where

这些module declarations指定您正在编译的模块的名称,以及导出的值。使用第一个声明,只从模块导出main;在第二种情况下,导出每个顶级值。无法从模块外部访问未导出的值,这就是GHCi中出现“不在范围内”错误的原因。

GHCi的不一致行为可能是为了使测试代码更容易;您不必拥有模块声明来加载文件并使用其定义。解决方案是将module Main where(或其他模块名称)放在文件的顶部,显式导出所有内容。就个人而言,我认为这种行为令人困惑,GHC和GHCi的行为应该改变为一致。

答案 1 :(得分:1)

语言标准规定,如果没有给出模块声明,则隐式module Main (main) where。当编译Haskell源文件然后将其加载到ghci时,只有相关模块的导出实体在范围内。在您的情况下,没有模块声明,那只是main函数。

但是,由于开发时非常不方便,ghci可以加载范围更广的解释模块,参见the users' guide。以该形式加载的模块在提示中的模块名称前用星号表示,对于此类模块,不仅模块中定义的每个顶级实体都在范围内,而且还有导入的实体,范围内的所有内容都在顶部 - 当以该形式加载模块时,在ghci提示符下也可以使用模块的级别。

这样可以方便地测试开发中的功能,因此是Good Thing™。另一方面,正如@ehird合理地提到的那样,行为上的差异可能令人困惑,因此是一件坏事。

总的来说,我认为ghci更广泛的*Module范围的优势超过了不一致性。

答案 2 :(得分:0)

很难准确猜出问题所在。您是否更改了文件顶部的行:

module Main where

类似于:

module Main (main) where

如果你这样做,它只会导出main函数。

答案 3 :(得分:0)

您之前可能已经编译过该模块,因此目录中存在.o.hi个文件。当GHCi找到它们时,默认情况下它将以编译模式加载模块,这意味着只有从模块导出的东西在范围内。

如果您没有包含模块声明,默认情况下这只是main,因为默认模块声明为module Main (main) where。这也是Main名称的来源。

您可以从提示中看出这种情况。通常,加载模块时,它看起来像这样:

Prelude> :load Foo.hs
[1 of 1] Compiling Main             ( Foo.hs, interpreted )
Ok, modules loaded: Main.
*Main> 

Main之前的星号表示模块在解释模式下打开,并且其中的所有内容都在范围内,包括从其他模块导入的内容。但是,如果我刚编译Foo.hs然后尝试将其加载到GHCi中,我会看到类似这样的内容:

Prelude> :load Foo.hs
Ok, modules loaded: Main.
Prelude Main> 

您可以通过在文件名前加上星号前缀来强制解释模式:

Prelude> :load *Foo.hs
[1 of 1] Compiling Main             ( Foo.hs, interpreted )
Ok, modules loaded: Main.
*Main> 

答案 4 :(得分:0)

不确定这是否有帮助,但我遇到了同样的问题。

原来我运行GHCI的虚拟空间不足,所以当我保存文件时它们是空的。

尝试加载文件看起来像是成功的(Whatever.hs,解释) - 但我得到了同样的错误。