Haskell IO 递归

3
我有这段代码:
read :: IO [Line]
read = do
  line <- getLine
  let count = length line
  line2 <- getLine 
  if (length line2 /= count) 
  then error "too long or too short"
  else read

我想要做的是,基于用户输入的第一行长度,让用户再输入长度-1的行。如果任何一行的长度不同于原始行,将显示错误消息。

现在我的代码只是一个无限循环,因为我无法找到如何输入长度-1的更多行的方法。对此的一些指导将不胜感激。

编辑:行的类型为字符串


你的代码陷入无限循环的原因是因为唯一允许它停止的方式是出现错误。否则,它将始终遵循if语句的另一个分支并不断递归。 - Dan Burton
1个回答

5
你可以使用replicateM函数来重复执行一个动作并收集结果。在你的情况下,这个动作是获取一行,测试其长度,并在无效时报错。因此,你可以使用以下类似的代码来完成你的工作:
import Control.Monad (replicateM)

read :: IO [Line]
read = do
  line <- getLine
  let count = length line
  lines <- replicateM (count-1) $ do
    line <- getLine
    if length line /= count
    then fail "too long or too short"
    else return line
  return $ line : lines

谢谢!ReplicateM看起来很不错,尽管它似乎在必要时没有停止(它超过了计数-1的限制!) - gdrules
2
replicateM 的运行完美无瑕,如果出现问题,很可能是在您的其余代码中。当标准的简单代码似乎完全无法实现其目的时,采取合理的立场就是不要指责标准函数并在自己的代码中寻找错误。如果您仍然找不到错误,请向一些经验丰富的 Haskell 开发人员展示您的代码,可以在这里或 #haskell 上寻求帮助。如果他们仍然找不到错误,那么就应该开始怀疑标准库了。 - Jedai
我想,刚才的代码看起来还不错,我会继续调试看看能否找到解决方法...谢谢。 - gdrules

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接