【问题标题】:Why is my Haskell code saying 'variable not in scope: main'?为什么我的 Haskell 代码说“变量不在范围内:主要”?
【发布时间】:2023-04-02 22:45:01
【问题描述】:

当我在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)

我已经尝试理解这个错误并想出一个解决方案几个小时了,但我离找到解决方案或理解错误的含义还差得远。

【问题讨论】:

  • 一个程序需要一个入口点:一个名为main的一元函数。
  • 你写的不是真的。代码不完整(我想念main)。另外,请查看let it be。我建议从头开始阅读那本书。

标签: haskell compiler-errors


【解决方案1】:

Haskell REPL (GHCi) 和实际的 Haskell 程序有很大不同。

造成这种差异的原因是两种格式的目标。首先,GHCi 是一个测试区,而不是代码运行区。然而,Haskell 源文件是为了运行一个特定的进程,它被命名为main。当您运行源文件时,Haskell 编译器(通常是 GHC)会查找名为 mainIO 操作,并尝试运行它。在这种情况下,没有main,所以它失败了。

其次,您输入的不是有效的 Haskell 程序,这些声明在 GHCi 中可以使用,但在 Haskell 源代码中则不行。这在源文件中是正确的:

squareMe x = x * x

myFruit = ["banana", "apple", "kiwi", "orange"]

注意缺少let; Haskell 源文件不使用它来声明事物。

请注意,在 repl.it 上,这仍然会抱怨缺少 main,但您可以放心地参考 REPL 中的 squareMemyFruit。换句话说,错误仍然会出现,但没关系,因为您仍然可以使用您在文件中写入的任何内容。

如果你想抑制警告,你可以写下这些行:

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 将在您运行时打印 ["banana", "apple", "kiwi", "orange"]

请注意,这个答案主要适用于站点 repl.it,尽管通常这是 Haskell 程序的结构。

【讨论】:

    【解决方案2】:

    如果您编译 Haskell 源代码,则需要有一个 main 符号作为入口点,就像编译时一样。一个C程序。同样在编译文件中,您必须跳过lets。例如

    squareMe x = x * x
    
    main = putStrLn . show $ squareMe 4
    

    【讨论】:

    • 没有必要在print 中使用show:这在输入类型上已经是多态的了。
    • print x = putStrLn (show x),因此您的代码调用了两次show
    • @leftaroundabout,确实如此。 print 可能甚至不应该出现在前奏中,因为一旦您想将多个值的输出拼凑在一起,或者添加换行符或其他任何内容,它就会成为错误的功能。 print = putStrLn . showreadLn = readIO =&lt;&lt; getLine,而且这些便利功能似乎都不值得花费教学费用。
    • @dfeuer 我觉得print 太方便了,无法同意这一点。事实上,我更倾向于说ShowRead 不应该出现在前奏中。 (人们应该很少觉得需要将任何内容转换为字符串,except 是为了对这些字符串进行 IO。)
    • 谢谢,编辑了答案并将print 替换为putStrLn
    【解决方案3】:

    如果您正在编写的更像是一个库或一组实用程序而不是一个完整的程序,您可以将其声明为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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-14
      • 1970-01-01
      • 1970-01-01
      • 2021-01-05
      相关资源
      最近更新 更多