如何使用putStr在Haskell中打印2个元素?

5

我是Haskell的新手,想知道如何在Haskell中打印两个函数的结果。在C++中,我会这样做:

cout << f() << g();

或者在 c# 中:

Console.WriteLine(f() + " " + g());

在Haskell中,我尝试了类似于以下的操作:
main =
    --putStr ( show $ square 3 )
    putStr ( show $ fibSeries 12 ) 

square :: Int -> Int
square x = x * x

fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

fibSeries :: Int -> [Int]
fibSeries x = map fib [0..x]

但是我必须注释掉第一个命令,因为它给我带来了编译时错误。

错误信息如下:

src\Main.hs:21:5:
    Couldn't match expected type `(String -> IO ()) -> String -> t0'
                with actual type `IO ()'
    The function `putStr' is applied to three arguments,
    but its type `String -> IO ()' has only one
    In the expression:
      putStr (show $ square 3) putStr (show $ fibSeries 12)
    In an equation for `main':
        main = putStr (show $ square 3) putStr (show $ fibSeries 12)

那不像是真正的代码。实际的代码和实际的错误是什么? - shachaf
2个回答

14

简而言之 你已经非常接近了!

main = do
    putStr ( show $ square 3 )
    putStr ( show $ fibSeries 12 )

请注意,这不会添加任何空格,您可能希望插入putStr " "


这里是发生的事情:Haskell的主要部分是纯函数式语言,没有“计算/动作顺序”的概念。如果您编写两行包含像print 5这样的语句,它们只会被解析为一行。

print 5 print 5

这意味着以下内容:print 是一个函数,它接受参数 5print5,并返回 main 的类型(一个 IO 动作)。因此类型需要是类似于

type PrintType = Int -> PrintType -> Int -> IO()

这显然是胡扯。要让Haskell实际上执行动作链(在命令式语言中经常做但在函数式编程中很少需要),我们有一个不错的do符号,它的工作方式很大程度上(但并非总是完全!)像你从命令式角度期望的那样。

要理解它的真正工作原理,你需要学习单子。这些在任何像样的Haskell教程中都有解释。可以阅读LYAH或其他资料。


关于您的代码的进一步说明:实际上,按顺序执行打印任务没有多大意义。你只需生成一个包含所需所有信息的字符串,然后一次性打印即可:

main = putStrLn $ show (square 3) ++ " " ++ show (fibSeries 12)

或者,如果您并不太关心格式,只是想获取信息,

main = print ( square 3, fibSeries 12 )

这将导致输出结果为(9,[0,1,1,2,3,5,8,13,21,34,55,89,144])


你可以插入 putStr " ",或者你可以用 putStrLn 替换 putStr,这样每个输出就会出现在单独的一行上。 - AndrewC
另外,如果你想要一个不涉及单子(monad)的do记法(do notation)介绍,可以阅读这篇文章。链接 - Gabriella Gonzalez

2
除了do符号外,您还可以使用sequence_函数执行一系列独立的IO操作:
main = sequence_ [putStr $ show $ square 3 ,
                  putStr $ show $ fibSeries 12]

2
我认为 mapM_ (putStr . show) [square 3, fibSeries 12] 更重要。此外,您可以省略括号:, 的“优先级”甚至比 $ 还要低。 (许多 Haskell 程序员更喜欢将其放在下一行的开头,并与 [ 对齐。) - leftaroundabout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接