简单的haskell代码无法编译

时间:2014-04-13 22:48:22

标签: haskell

我开始学习Haskell,只是尝试了一个简单的代码,它在我运行时向我显示了一些错误

doubleMe :: Int -> Int
doubleMe x = x + x

main = do
    doubleMe 2
  

ghc -c first.hs

错误是:

  

$ ghc -c first.hs

     

first.hs:4:1:       无法匹配预期类型IO t0' with actual type Int'       在表达式中:main       检查函数“main”的类型时

虽然我使用GCHi进行调试,但首先加载doubleMe函数并稍后调用它没有问题。任何帮助将不胜感激。

5 个答案:

答案 0 :(得分:6)

main必须是IO a类型的值,doubleMe 2的类型为Int。您可能想要print值:

main = print (doubleMe 2)

答案 1 :(得分:6)

Haskell中的每个函数都返回某种类型的值。

在这种情况下,doubleMe函数返回Int类型的值。从ghci解释器加载文件时,它会加载文件中的所有函数并使它们可供您使用。

main函数是一个稍微特殊的函数,与其他语言非常相似。它定义了Haskell程序的入口点。但是,由于它只是另一个Haskell函数,它也必须返回特定类型的值。 main函数被约束为返回IO类型的值,最常见的是IO ()

IO本身也很特别,属于一类叫做monads的类型。您可以阅读IO monad here.

现在让我们回到你的代码:

main = do
    doubleMe 2

暂时忽略do语法。您基本上告诉编译器main函数返回类型为doubleMe 2的{​​{1}}。这不会飞。 Int 返回main类型的值。在这种情况下,您可以使用IO函数将return值转换为Int值。 (IO Int函数是所有monadic类型必须具有的函数。非常简单地说,它将任何类型的值转换为monadic值。)

所以这就变成了:

return

这是完全有效的代码,并将进行编译。但是,一旦你运行程序,你会发现它没有做任何事情。那是因为程序返回值4。 实际上,你可以在没有do的情况下编写它,它变为:

main = do
    return (doubleMe 2)

这也可以。

但是,让我们假设您要打印出值。这就是main = return (doubleMe 2) 真正进入的地方。打印到屏幕是IO动作。

IO

main = do print (doubleMe 2) return (doubleMe 2) 表达式允许您链接一组do个动作。因此,您的程序仍将返回值IO,但它将首先评估表达式4。正如预期的那样,实际上会导致打印值print (doubleMe 2)。 检查ghci中的doubleMe 2函数。

print

打印功能适用于任何可以显示的类型的值,并且会导致> :t print print :: Show a => a -> IO () 操作(打印到屏幕)但不返回IO

所有这些例子都有效,希望能让事情变得清晰。 (查看())的类型签名。

main

答案 2 :(得分:3)

它不起作用,因为使用符号的任何内容都必须返回monad。 GHCI做了一些事情来使它更有用,但它并不像GHC编译的代码那样完全有效。

print :: Show a => a -> IO ()

print获取的值为Show的实例,并返回空的IO操作。这很可能是你想要做的。

main = print (doubleMe 2)

应该像你想做的那样工作。您没有定义main函数的类型,但在haskell中必须具有类型main :: IO ()。查看doubleMe的类型,您可能会看到为什么您的代码不起作用。

答案 3 :(得分:1)

您的main函数不执行任何操作并返回整数。你可能想要

doubleMe :: Int -> Int
doubleMe x = x + x

main = do
    print $ doubleMe 2

而是输出4到STDOUT。

恭喜,您已遇到Monadsmain是一个IO monad,必须这样做。 IO monads不返回Int s。相反,IO Monad是一个IO动作,由print返回并在运行时执行。

答案 4 :(得分:0)

幕后发生的一些事情使得很难理解这个错误信息。这是推理:

  1. 您的文件没有模块名称,因此ghc假定您正在定义模块Main
  2. 模块main中的名称Main必须包含IO something类型。
  3. 但您撰写的main类型为Int
  4. IO somethingInt不同,无论我们为something选择什么。
  5. GHC仅报告最后一步。

    如果要打印Int,可以使用print构建IO操作:

    main = do
      print (doubleMe 2)
    

    这个问题没有出现在ghci中,因为在那里,你可以输入你想要的任何类型的表达式。如果类型为IO something,ghci将为您执行IO操作。 (例如:readFile "foo.txt")。如果类型不是IO something,ghci将添加对print的调用,然后执行该IO操作(例如:['a' .. 'z'])。

    在源文件中,如果您需要或需要,您必须自己将呼叫添加到print