我开始学习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
函数并稍后调用它没有问题。任何帮助将不胜感激。
答案 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。
恭喜,您已遇到Monads。 main
是一个IO monad,必须这样做。 IO monads不返回Int
s。相反,IO Monad是一个IO动作,由print
返回并在运行时执行。
答案 4 :(得分:0)
幕后发生的一些事情使得很难理解这个错误信息。这是推理:
Main
。main
中的名称Main
必须包含IO something
类型。main
类型为Int
。IO something
与Int
不同,无论我们为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
。