Haskell - 循环用户输入

use*_*343 11 io haskell

我在haskell中有一个程序,它必须从用户读取任意输入行,当用户完成时,必须将累积的输入发送到函数.

在命令式编程语言中,这将是这样的:

content = ''
while True:
    line = readLine()
    if line == 'q':
        break
    content += line
func(content)
Run Code Online (Sandbox Code Playgroud)

我发现这在哈斯克尔难以置信,所以我想知道是否有相似的哈希尔.

nic*_*kie 17

相当于迭代的Haskell是递归.IO如果你必须阅读输入行,你还需要在monad中工作.总体情况是:

import Control.Monad

main = do
  line <- getLine
  unless (line == "q") $ do
    -- process line
    main
Run Code Online (Sandbox Code Playgroud)

如果您只想累积所有读取行content,则不必这样做.只需使用getContents将检索(懒惰)所有用户输入.当你看到时,就停下来'q'.在非常惯用的Haskell中,所有阅读都可以在一行代码中完成:

main = mapM_ process . takeWhile (/= "q") . lines =<< getContents
  where process line = do -- whatever you like, e.g.
                          putStrLn line
Run Code Online (Sandbox Code Playgroud)

如果您从右到左阅读第一行代码,它会说:

  1. 得到用户将提供的所有内容作为输入(从不担心,这是懒惰的);

  2. 将它分成线条;

  3. 只要它们不等于"q",只取线,当你看到这样的线时停止;

  4. 并呼吁process每一行.

如果您还没有弄明白,那么您需要仔细阅读Haskell教程!


Chr*_*lor 7

在Haskell中它相当简单.最棘手的部分是你想要累积用户输入的序列.在命令式语言中,您使用循环来执行此操作,而在Haskell中,规范方法是使用递归辅助函数.它看起来像这样:

getUserLines :: IO String                      -- optional type signature
getUserLines = go ""
  where go contents = do
    line <- getLine
    if line == "q"
        then return contents
        else go (contents ++ line ++ "\n")     -- add a newline
Run Code Online (Sandbox Code Playgroud)

这实际上是一个返回a的IO动作的定义String.由于它是IO操作,因此使用<-语法而不是=赋值语法访问返回的字符串.如果您想快速浏览一下,我建议您阅读IO Monad,对于那些根本不关心的人.

您可以在GHCI提示符下使用此功能

>>> str <- getUserLines
Hello<Enter>     -- user input
World<Enter>     -- user input
q<Enter>         -- user input
>>> putStrLn str
Hello            -- program output
World            -- program output
Run Code Online (Sandbox Code Playgroud)

  • 现在,你真的会用 Haskell 写这个吗?每次将“line”附加到“contents”都会导致性能不佳。您最终想要的“contents”是对“getContents”的一次调用将为您提供的前缀。 (2认同)