当我在repl.it网站上的Haskell交互式shell中输入以下内容时,它运行正常。
let squareMe x = x * x
let myFruit = ["banana", "apple", "kiwi", "orange"]
但是当我将其输入源文件并单击“运行”时,我收到错误:
<interactive>:3:1: error:
• Variable not in scope: main
• Perhaps you meant ‘min’ (imported from Prelude)
我一直在努力理解这个错误,并且现在提出了几个小时的解决方案,并且没有找到解决方案或理解错误意味着什么。
答案 0 :(得分:12)
Haskell REPL(GHCi)和实际的Haskell程序有很大不同。
造成这种差异的原因是两种格式的目标。首先,GHCi是一个测试区域,而不是代码运行区域。但是,Haskell源文件用于运行某个名为main
的进程。当您运行源文件时,Haskell编译器(通常是GHC)会查找名为IO
的{{1}}操作,并尝试运行它。在这种情况下,没有main
,所以它失败了。
其次,你输入的内容不是有效的Haskell程序,那些是在GHCi中可以正常的声明,但在Haskell源中却没有。这在源文件中是正确的:
main
注意缺少squareMe x = x * x
myFruit = ["banana", "apple", "kiwi", "orange"]
; Haskell源文件不会用它来声明事物。
请注意,在repl.it上,这仍然会导致let
丢失,但您可以毫无顾虑地在REPL中引用main
和squareMe
。换句话说,错误仍然会出现,但它并不重要,因为你可以使用你在文件中写的任何内容。
如果您想要取消警告,可以写下以下行:
myFruit
你可以让程序做很多事情而不是这个。以下是几个例子:
main :: IO () -- This says that main is an IO action.
main = return () -- This tells main to do nothing.
运行时会打印main = putStrLn "No errors!"
。No errors!
运行时会打印main = print myFruit
。请注意,这个答案主要适用于网站repl.it,但一般来说这就是Haskell程序的结构。
答案 1 :(得分:4)
如果编译Haskell源,则需要有一个main
符号作为入口点,就像编译例如一个C程序。同样在编译文件中,您必须跳过let
。 E.g。
squareMe x = x * x
main = do
putStrLn (show (squareMe 4))
答案 2 :(得分:0)
如果您正在编写的内容更像是一个库或一组实用程序例程而不是一个完整的程序,则可以将其声明为module
。然后GHC会将其编译为可以链接到其他程序的对象,您也可以将其加载到GHCI中。它不会包含main
例程。
如果将其保存到.hs
文件:
module Example (squareMe) where
squareMe x = x * x -- Exported to other modules.
myFruit = ["banana", "apple", "kiwi", "orange"] -- Not exported.
使用GHC进行编译将为您提供.hi
文件和.o
文件,并在GHCI中运行它将为您提供:
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Ok, modules loaded: Example (sx-modulexmpl.o).
Prelude Example> squareMe 2
4
您还可以从命令行计算引用库的表达式。 ghc -e "squareMe 2" Example.hs
打印4
。