【问题标题】:Couldn't match expected type `IO b0' with actual type `[a0]'无法将预期类型“IO b0”与实际类型“[a0]”匹配
【发布时间】:2012-11-03 18:28:49
【问题描述】:

我是haskell 的新手。我正在尝试编写一个 gcd 可执行文件。

ghc --make gcd

当我编译此代码时,我收到以下错误。

Couldn't match expected type `IO b0' with actual type `[a0]' 
In a stmt of a 'do' block:
  putStrLn "GCD is: " ++ gcd' num1 num2 ++ "TADA...."
In the expression:
  do { putStrLn "Hello,World. This is coming from Haskell";
       putStrLn "This is the GCD";
       putStrLn "Frist Number";
       input <- getLine;
       .... }
In an equation for `main':
    main
      = do { putStrLn "Hello,World. This is coming from Haskell";
             putStrLn "This is the GCD";
             putStrLn "Frist Number";
             .... }

我不明白我的问题出在哪里...这是我的代码。

gcd' :: (Integral a) => a -> a -> a
gcd' x y = gcd' (abs x) (abs y)
      where gcd' a 0  =  a
        gcd' a b  =  gcd' b (a `rem` b)

main = do
    putStrLn "Hello,World. This is coming from Haskell"
    putStrLn "This is the GCD"
    putStrLn "Frist Number"
    input <- getLine
    let num1 = (read input)
    putStrLn "Second Number"
    input2 <- getLine
    let num2 = read input2
    putStrLn "GCD is: " ++ gcd' num1 num2 ++ "TADA...."

我只知道read 帮助我将字符串转换为int。

【问题讨论】:

    标签: haskell greatest-common-divisor


    【解决方案1】:

    首先,你需要括号,

    putStrLn ("GCD is: " ++ gcd' num1 num2 ++ "TADA....")
    

    或中缀函数申请($):

    putStrLn $ "GCD is: " ++ gcd' num1 num2 ++ "TADA...."
    

    否则,该行将被解析为

    (putStrLn "GCD is: ") ++ gcd' num1 num2 ++ "TADA...."
    

    IO 操作 putStrLn "GCD is: "String 的串联是导致 - 在一个有足够经验之前有点神秘 - 类型错误的原因。

    根据该行出现的上下文 - 在IO-do-block 中 - 对于某些b,它必须具有类型IO b。但是从(++) 的应用中推断出的类型是[a] 对于某些类型a。这些类型无法匹配,这就是编译器报告的内容。

    请注意,修复该问题后,您还需要将gcd' 的结果转换为String

    putStrLn $ "GCD is: " ++ show (gcd' num1 num2) ++ "TADA...."
    

    否则你会看到另一个类型错误。


    来自评论

    为了让我的程序看起来更好。有没有办法让输入区域就在语句旁边而不是下一行?

    一般来说,是的。不要使用putStrLn 将换行符附加到输出字符串,而使用putStr 不会。

    putStr "Second Number: "
    input2 <- getLine
    

    在交互模式 (ghci) 下,效果很好。 stdout 没有在那里缓冲。对于已编译的程序,stdout 通常是行缓冲的,这意味着它不会输出任何内容,直到输出换行符或缓冲区已满。

    所以对于一个编译好的程序,你需要显式地刷新输出缓冲区,

    import System.IO -- for hFlush
    
    putStr "Second Number: "
    hFlush stdout
    input2 <- getLine
    

    或完全关闭缓冲

    import System.IO
    
    main = do
        hSetBuffering stdout NoBuffering
        ...
    

    但至少后一种方法过去在 Windows 上不起作用(我不确定这是否已修复,我也不确定hFlushing 在 Windows 上是否有效)。

    【讨论】:

    • 为了让我的程序看起来更漂亮。有没有办法让输入区域就在语句旁边而不是下一行?
    • 当然(通常),我会将其添加到答案中,因为关于缓冲的一点可能不适合评论。
    • 使用putStr 代替putStrLn?究竟发生了什么,哪个 GHC 版本,哪个平台?
    • 如果你只想要结果:计算 gcd 在 O(log (min{|x|, |y|}+1) + 1) 步骤(+1 以避免@987654348 @ 问题,并处理 0 输入的一步)。如果您想知道如何计算它,那么解释的时间比这里适合的要长得多。也许wikipedia 解释了它。在TAOCP中有解释,可以从连分数算法中推导出来,...
    • “每次都编译”是什么意思?你编译一次,你会得到一个可以随时运行的二进制文件。上面的代码提示输入,但您也可以在命令行上传递参数并通过System.Environment.getArgs 获取它们。如果您的意思是在不编译的情况下运行代码,1. 有 ghci(i 在交互中),2. runhaskell(运行带有main 的程序而不编译,好吧,解释,字节码)。
    猜你喜欢
    • 2021-11-13
    • 1970-01-01
    • 2017-09-16
    • 2015-06-08
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多