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)
4

2 回答 2

14

tl; 博士你离得太近了!

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

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


这是发生了什么:Haskell 的主要部分,纯函数式语言,没有任何诸如“计算/动作顺序”之类的东西。如果你用类似的语句写两行print 5,它们只会被解析为一行,即

print 5 print 5

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

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

这当然是胡说八道。为了告诉 Haskell 你实际上想要对一系列动作进行排序(你在命令式语言中一直这样做,但在函数式编程中很少需要),我们有这个很好的do符号,它很有效(但并不总是完全正确!)就像您从命令的角度所期望的那样。

要了解它的真正工作原理,您需要了解 monad。这些在任何体面的 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])

于 2013-06-24T09:03:32.867 回答
2

除了 do 表示法,您还可以使用sequence_函数来执行一系列独立的IO操作:

main = sequence_ [putStr $ show $ square 3 ,
                  putStr $ show $ fibSeries 12]
于 2013-06-24T12:25:40.463 回答