Итак, я хотел создать программу, которая печатает треугольник 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

Я получаю ошибку

• 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
3
m3k_1 20 Май 2021 в 21:45

2 ответа

Лучший ответ

Во-первых, вам не хватает do здесь:

      then
        triangle number'*'
        main 

Две строки после then интерпретируются вместе как triangle number '*' main (именно так они цитируются в сообщении об ошибке, если вы заметили). Чтобы две строки интерпретировались отдельно как последующие действия, они должны находиться внутри do:

      then do
        triangle number'*'
        main 

И та же проблема, плюс неоднозначный отступ, существует с самым последним блоком. Вероятно, это должно быть:

else do
  triangle number '#'
  main
4
Fyodor Soikin 20 Май 2021 в 19:07

Ошибка говорит:

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

Итак, компилятор проанализировал ваш код как triangle number '*' main; это означает, что разрыв строки между triangle number '*' и main не интерпретируется как разрыв оператора блока do, и причина в том, что вы не внутри блока do ! Та же ошибка возникает в последующем предложении else для 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

Если у вас возникли проблемы с правилами компоновки 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

Кроме того, обратите внимание, что я помещаю пробелы вокруг символьного литерала, например … number '*' … вместо … number'*' …. В идентификаторах разрешены апострофы (как ASCII-аппроксимация «простого» символа ), поэтому, если вы измените его на number'X', тогда это будет проанализировано как одно имя, {{X3 }}, а не имя number, за которым следует символьный литерал 'X', что может сбивать с толку.

4
Jon Purdy 20 Май 2021 в 19:10