【问题标题】:Error with recursive IO递归 IO 出错
【发布时间】:2017-06-10 19:00:10
【问题描述】:

为什么这段代码不起作用?

xMal 0 _ = return ()
xMal n text =
 do
  text
    xMal (n-1) text
main = xMal (putStrLn t <- getLine) (n <- readLn)

我希望能够得到一个数字和字符串作为输入。

【问题讨论】:

  • 对于初学者来说,您没有使用正确的语法。仅供参考,将来最好包含您认为您的函数应该是的类型签名,正确格式化您的代码,并包含编译器错误。
  • 你认为putStrLn t &lt;- getLine应该做什么?将n &lt;- readLn 作为参数传递给函数是什么意思?
  • ...并确保清楚预期的行为是什么 :)
  • &lt;- 不是运算符;它是do 表达式语法的一部分。

标签: haskell recursion io


【解决方案1】:

Haskell 不是这样工作的,使用您的 &lt;- 表达式,您进行单子调用,这些应该按正确的顺序放置。你可能想要:

xMal 0 _ = []
xMal n text = text : xMal (n-1) text

main = do
    n <- readLn
    t <- getLine
    putStrLn $ show $ xMal n t

这里的xMal 是一个纯函数:xMal :: (Eq a, Num a) =&gt; a -&gt; t -&gt; [t],它复制给定的t 对象a 次。

main 是一个 IO monad,它从标准输入读取一行并将其解析为整数,然后将一行读取为字符串,最后显示复制的字符串。比如:

*Main> main
15
Hello
["Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello"]

但请注意,您的 xMal 已经存在:replicate :: Int -&gt; a -&gt; [a] 已经这样做了。

【讨论】:

  • 值得一提的是xMal then 与此上下文中的标准replicate 函数(来自Prelude)相同
  • @jd823592:是的,这就是我说“复制”的原因。但答案已更新。
【解决方案2】:

正确的语法是:

   xMal 0 _    = return ()
   xMal n text = do                   -- or, indentation-proof:   
                   text               --  do { text
                   xMal (n-1) text    --     ; xMal (n-1) text }
   main = do {
               t <- getLine
             ; n <- readLn
             ; xMal n (putStrLn t) }

具有相同的缩进很重要。否则,{ ; } 用于以防空格的方式分隔语句。然后,损坏的缩进不会破坏代码。不过,正确排列我们的代码还是不错的。

putStrLn t :: IO () 是一个 I/O 操作,它在单独的行上打印其字符串参数 t。它还“产生”一个() 类型的值,以供链中的下一个 I/O 操作做出反应;这只能是一个值,也可以写成(),因此表示一个不重要的、丢弃的值,一个可以忽略的值。你也可以在你的do 块中写_ &lt;- text。只写text 具有相同的效果:生成的值被忽略。

在 GHCi 中尝试一下,

~> main
hello
3
hello
hello
hello

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    • 2013-12-06
    • 1970-01-01
    • 1970-01-01
    • 2019-03-26
    • 1970-01-01
    相关资源
    最近更新 更多