如何在 Haskell 中执行递归主函数

m3k*_*k_1 3 recursion haskell

所以我想制作一个打印出 ASCII 三角形的程序。程序会询问您希望三角形的高度并将其打印出来,直到您输入的数字为7为止,然后绘制高度为 7 的三角形,程序停止。如果数字是偶数,则打印出的三角形由“*”组成,如果数字是奇数,则由“#”组成。我想通过递归调用main函数来做到这一点

triangle level character = draw level character 1 
      where draw level character accumulator
             | level <=0 = putStr("")
             | level > 0 = do 
                 putStrLn (replicate level ' ' ++ replicate accumulator character)
                 draw (level-1) character (accumulator+2)

main = do
    number <- readLn :: IO Int
    if(number `mod` 2 == 0)
      then
        triangle number'*'
        main 
     else if (number == 7)
       then triangle number '#'
       else triangle number '#'
       main
Run Code Online (Sandbox Code Playgroud)

我得到的错误是

• Couldn't match expected type ‘IO () -> IO ()’
              with actual type ‘IO ()’
• The function ‘triangle’ is applied to three arguments,
  but its type ‘Int -> Char -> IO ()’ has only two
  In the expression: triangle number '*' main
  In a stmt of a 'do' block:
    if (number `mod` 2 == 0) then
        triangle number '*' main
    else
        if (number == 7) then
            triangle number '#'
        else
            triangle number '#' main
Run Code Online (Sandbox Code Playgroud)

Jon*_*rdy 7

错误说:

• The function ‘triangle’ is applied to three arguments,
  but its type ‘Int -> Char -> IO ()’ has only two
  In the expression: triangle number '*' main
Run Code Online (Sandbox Code Playgroud)

所以编译器已将您的代码解析为triangle number '*' main; 这意味着triangle number '*'和之间的换行符main不会被解释为do块语句中断,原因是您不在do块内!同样的错误出现在后面的elsefor 子句中triangle number '#' main。解决方法是添加一个do

main = do
    number <- readLn :: IO Int
    if(number `mod` 2 == 0)
      then do
        triangle number'*'
        main 
     else if (number == 7)
       then triangle number '#'
       else do
         triangle number '#'
         main
Run Code Online (Sandbox Code Playgroud)

如果你对 Haskell 的布局规则有疑问,你总是可以使用显式花括号{......}围绕块和;块项之间的分号,以检查你对代码是如何解析的理解。

main :: IO ();  -- end signature
main = do {  -- begin ‘do’
    number <- readLn :: IO Int;  -- end statement
    if (number `mod` 2 == 0)
      then do {
        triangle number '*';
        main;
      }
      else if (number == 7)
      then triangle number '#'
      else do {
        triangle number '#';
        main;
      };  -- end ‘do’, end statement (starting with ‘if…’)
};  -- end ‘do’, end equation
Run Code Online (Sandbox Code Playgroud)

另外,请注意,我在字符文字周围放置了空格,… number '*' …而不是… number'*' …. 标识符中允许使用撇号(作为“素数”符号的 ASCII 近似值 ? ),因此如果您将其更改为 ,number'X'那么它将被解析为单个名称number'X',而不是名称number后跟字符文字'X',这可能会造成混淆。


Fyo*_*kin 6

首先,您在do这里缺少一个:

      then
        triangle number'*'
        main 
Run Code Online (Sandbox Code Playgroud)

后面的两行then被一起解释为triangle number '*' main(如果您注意到,这是错误消息中引用的方式)。为了将这两行分别解释为后续操作,它们需要在 a 中do

      then do
        triangle number'*'
        main 
Run Code Online (Sandbox Code Playgroud)

同样的问题,加上模棱两可的缩进,存在于最后一个块中。大概应该是:

else do
  triangle number '#'
  main
Run Code Online (Sandbox Code Playgroud)