如何在此代码中使用循环而没有任何错误?

时间:2012-01-16 06:46:09

标签: haskell loops

这是一个程序,以便GHC从用户获取数字n,然后它形成n个数字的列表,这些数字再次由用户给出。此代码显示循环的一些解析错误。我该如何删除该错误?

import System.IO

main = do 
   putStrLn "Please enter the number"
   number <- readLn :: IO Int
   putStrLn $ "The num is:" ++ show number
   loop number
   xs <- sequence [readLn :: IO Int]
   putStrLn xs

loop:: Int -> IO ()
loop n = if 0==n then return () else return loop (n-1)

3 个答案:

答案 0 :(得分:2)

除了其他答案所说的:

您不需要编写循环函数。

import System.IO

main = do 
   putStrLn "Please enter the number"
   number <- readLn :: IO Int
   putStrLn $ "The num is:" ++ show number
   xs <- sequence (replicate number (readLn :: IO Int))  -- pay attention to this line
   print xs

所以我们从readLn开始。 replicate列出了number readLn个。 (根据您的观点,您可能认为这是一个聪明的位。)

聪明的位:sequence获取IO操作列表,并将其转换为一个大的IO操作。每个readLn依次发生,收集返回值并在列表中返回。

答案 1 :(得分:0)

您的代码中有三个错误。复制并在GHC中启动它会显示以下消息:

temp.hs:9:13
    Couldn't match expected type `Char' with actual type `Int'
    Expected type: String
      Actual type: [Int]
    In the first argument of `putStrLn', namely `xs'
    In the expression: putStrLn xs

这个很清楚。 putStrLn需要String,但xsInt的列表。因此,只需使用print xs代替putStrLn xs即可解决问题(print = putStrLn . show)。

接下来的两个实际上是关于同样的问题:

    temp.hs:13:38:
        No instance for (Monad ((->) t0))
          arising from a use of `return'
        Possible fix: add an instance declaration for (Monad ((->) t0))
        In the expression: return loop (n - 1)
        In the expression:
          if 0 == n then return () else return loop (n - 1)
        In an equation for `loop':
            loop n = if 0 == n then return () else return loop (n - 1)

temp.hs:13:45:
    Couldn't match expected type `IO ()'
                with actual type `Int -> IO ()'
    In the first argument of `return', namely `loop'
    In the expression: return loop (n - 1)
    In the expression:
      if 0 == n then return () else return loop (n - 1)

问题在于类型。 loop的类型为Int -> IO ()。所以函数的第一个分支是正常的,因为你return ()。但是,在else分支中,您返回的内容完全不同,因为return不是语言的内置语句,而是正常函数。因此return loop (n - 1)首先将您的loop函数提升为monad,然后将其应用于(n - 1)

相反,你想要的是:

loop n = if n == 0 then return () else loop (n - 1)

另请注意,在Haskell中不需要0 == n,因为没有办法意外地使用赋值而不是相等比较(它不会编译)。

编辑:正如其他答案指出的那样,loop并没有真正做任何事情 - 它只调用自己n-1次然后返回()。

答案 2 :(得分:0)

如果我理解你的意图,你的意思是创建一个“循环”结构,它将执行 n 次动作,并生成一个结果列表。在您拥有的代码中,

loop number
xs <- sequence [readLn :: IO Int]

但这两个陈述是分开的;您需要发送您希望重复的行动loop 作为inut:

xs <- loop number readLn :: IO [Int]

当然,您需要重写loop以接受操作作为参数

loop :: Int -> IO a -> IO [a]
loop 0 action = return []  -- don't perform the action
loop n action = do
  x <- action              -- perform the action once
  xs <- loop (n-1) action  -- then perform it (n-1) times
  return (x:xs)            -- produce the resultant list

这里我用模式匹配编写了它,而不是if n == 0。我可以用“if”结构轻松地编写它,但我个人倾向于发现那些相当丑陋。

但是等等,标准库中可能存在类似的东西。停止...... Hoogle时间!为新loop a -> IO a -> IO [a]提供类型签名,我们发现replicateM

xs <- replicateM number readLn :: IO [Int]