【问题标题】:Haskell - What makes 'main' unique?Haskell - 是什么让“主要”与众不同?
【发布时间】:2011-09-09 15:48:34
【问题描述】:

使用此代码:

main :: FilePath -> FilePath -> IO ()
main wrPath rdPath = do x <- readFile rdPath
                        writeFile wrPath x

我收到以下错误:

Couldn't match expected type 'IO t0'
            with actual type 'FilePath -> FilePath -> IO()

但是当我将“main”的名称更改为其他名称时,文件编译正确。

main 有什么独特之处,为什么它的类型必须是 IO t0?

【问题讨论】:

    标签: haskell types io compiler-errors main


    【解决方案1】:

    因为语言规范says so。

    Haskell 程序是一组模块,按照惯例,其中一个必须称为Main,并且必须导出值main。程序的值是模块Main 中标识符main 的值,对于某些t 类型,它必须是IO t 类型的计算(参见第7 章)。当程序执行时,计算main被执行,其结果(t类型)被丢弃。

    【讨论】:

      【解决方案2】:

      正如 GolezTrol 所说,所有程序都需要知道在调用函数时要开始执行哪个符号。许多脚本语言不需要(或只是不需要)main 例程,因为它们可以将语句放在顶层。 Haskell、C 和许多其他语言的情况并非如此 - 这些语言需要一个起始位置,并且按照惯例,它是 main 函数(根据 Haskell 规范 - 请参阅 Cat 的答案)。

      注意 Haskell 的 main 不接受与程序参数相对应的任何参数 - 这些是通过 System.Environment.getArgs 获得的。

      【讨论】:

        【解决方案3】:

        与在 C、Java 或 C# 中一样,main 在某些上下文中是一个特殊标识符,指示程序应该从哪里开始。

        在 Haskell 中,main 被定义为具有 IO a 类型。你应该给你的函数一个不同的名字,或者如果你真的希望它成为起点,改变它的签名并让它从命令行读取参数getArgs

        虽然你没有特别问,main 也很特别,因为它是 Haskell 程序中唯一可以(安全地)调用 IO 操作的函数。 Haskell 运行时将main 视为特殊的。

        【讨论】:

          【解决方案4】:

          根据定义,main 是一个不接受参数并返回一个类型为 IO a 的值的函数,该值被运行时丢弃。您的错误消息是说您的 main 不符合这些要求。确实如此,因为您的main 接收两个参数。

          要访问命令行参数,请使用System.Environment.getArgs。

          【讨论】:

            【解决方案5】:

            Main.main 有什么独特之处?

            既然 Haskell 有一个 FFI,它比喻很简单:

            This code: (sort of) ends up as:
            module Main(main) where
            main :: IO ()
            ⋮
            ≈ module Main() where
            foreign export "Hmain" main:: IO ()
            ⋮

            (...“比喻地”,不是 “字面上” - 把这项工作留作练习;- )

            所以Main.main 的独特之处在于它默认在 Haskell 外部可见,允许运行时系统调用您的 Haskell 程序。对于任何其他 Haskell 定义,您都需要使用 FFI。


            为什么它的类型必须是IO t?

            因为在 Haskell 中,只有 IO ... 类型的值(通常称为 actions)可以产生可见的效果,例如写入文件。此外,运行时系统只有在IO动作时才能正确调用Main.main。

            【讨论】:

              【解决方案6】:

              我知道这个问题很古老,但我想我应该提一下,你可以在一个不(显式或隐式)命名为 Main 的模块中命名任何你想要的东西 main。所以

              module Foo where
              main :: Int -> Bool
              main = (>3)
              

              会编译得很好。但是如果你省略了模块头,或者使用module Main where ...,那就不会了。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-24
                • 2016-05-06
                • 2018-04-06
                • 1970-01-01
                相关资源
                最近更新 更多