在Haskell ghci,我试过
Prelude> :load filename.hs
Ok, modules loaded: Main.
遗憾的是,我无法运行文件中定义的任何功能。我编译了文件没有任何错误,但调用函数给出一个错误,“不在范围内:(函数名称)”。奇怪的是,一段时间之前,我没有遇到任何问题......
答案 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,解释) - 但我得到了同样的错误。