2014-04-13 155 views
0

我开始学习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” 在表达式:主 当检查功能的类型`主

虽然我使用GCHI调试,有没有问题先加载doubleMe函数,然后再调用它。任何帮助,将不胜感激。

+0

我建议使用ghci(交互式环境),所以你不必编译你的代码进行简单的手工测试。你可以只输入':l first.hs'来加载你的定义,然后输入'doubleMe 2',而不用每次都编辑 - 主要 - 我想要检查的东西。 (请参阅关于如何编写'main'的建议的答案。) – AndrewC

+0

哇...非常感谢所有人如此迅速地回答我的问题。 Haskell社区对新手的友好态度令我印象深刻。每个人的意见都可以被接受为答案,但由于只能接受一个答案,所以我选择@ tanmaig's,因为他有最彻底的解释。再次感谢你们! – Sapience

回答

5

在Haskell每个函数返回一个特定类型的值。

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

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

IO本身也比较特殊,属于一类monads。您可以在IO单子here.

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

main = do 
    doubleMe 2 

忽略do语法一会儿。您基本上告诉编译器main函数返回doubleMe 2,它是Int类型。这不会飞。 main已将返回值IO类型。在这种情况下,您可以使用return函数将Int值转换为IO Int值。 (return功能是所有单子的类型一定是很简单的把功能,将其转换任何类型的值,为一元值。)

所以这变为:

main = do 
    return (doubleMe 2) 

这是完全合法的代码,并将编译。但是,一旦你运行该程序,你会注意到它没有做任何事情。这是因为该程序返回值4 事实上,你可以写它没有做的,它变成:

main = return (doubleMe 2) 

这将工作过。

但让我们假设您想要打印出该值。这是IO确实进来的地方。打印到屏幕上的操作是IO

main = do 
      print (doubleMe 2) 
      return (doubleMe 2) 

do表达式允许您一组IO动作。所以你的程序仍然会返回值4,但它会首先评估表达式print (doubleMe 2)。如预期的那样,实际上导致打印值doubleMe 2。 检查ghci中的print函数。

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

打印功能适用于任何类型的,可以是所示的值和它导致IO动作(打印到屏幕),但没有返回()

所有这些例子都可以工作,并且希望能让事情变得清晰一些。 (查看main的类型签名)。

-- main :: IO Int 
main = return (doubleMe 2) 

-- main :: IO Int 
main = do 
      print (doubleMe 2) 
      return (doubleMe 2) 

-- main :: IO() 
main = do 
      print (doubleMe 2) 
      return() 

-- main :: IO() 
main = do 
      print (doubleMe 2) 

-- main :: IO() 
main = print (doubleMe 2) 

-- main :: IO() 
main = do 
     print "Hello" 
     print (doubleMe 2) 
     return() 

-- main :: IO String 
main = do 
     print "Hello" 
     print (doubleMe 2) 
     return "Hello" 
3

它不起作用,因为任何使用表示法都必须返回monad。 GHCI做了一些事情使它更有用,但它不像GHC编写的代码那样工作。

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

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

main = print (doubleMe 2)

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

+6

请不要说“返回monad”。这是草率的措辞,鼓励思路不清。作为monad是一个类型构造函数的谓词。函数返回值,而不是类型。保持类型和价值层次对于理解Haskell至关重要,在教初学者时我们应该特别小心。说一些像“'main'必须是'IO'值,而你的表达不是,”或者什么的。清楚准确地沟通真的很重要。 – Carl

+3

更不用说,它也是平淡的错误,“做”块必须导致单值类型的值。 'do()'完全有效。 – Carl

1

您的main函数不需要任何操作并返回一个整数。您可能想要

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

main = do 
    print $ doubleMe 2 

而是将4输出到标准输出。

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

6

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

main = print (doubleMe 2) 
0

有些事情发生在幕后,很难理解这个错误信息。这是推理:

  1. 您的文件没有模块名称,所以ghc假定您正在定义模块Main
  2. 模块Main中的名称main必须具有类型IO something
  3. 但你写的main的类型为Int
  4. IO somethingInt不一样,无论我们选择something

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