haskell - 读取多行用户输入

标签 haskell io

我想懒洋洋地读取用户输入并逐行执行某些操作。但是,如果用户以 , (逗号)后跟任意数量的空格(包括零)结束一行,我想给他机会在下一行完成输入。

这是我得到的:

import System.IO
import Data.Char

chop :: String -> [String]
chop = f . map (++ "\n") . lines
    where f [] = []
          f [x] = [x]
          f (x : y : xs) = if (p . tr) x
                           then f ((x ++ y) : xs)
                           else x : f (y : xs)
          p x = (not . null) x && ((== ',') . last) x
          tr xs | all isSpace xs = ""
          tr (x : xs) = x :tr xs

main :: IO ()
main =
    do putStrLn "Welcome to hell, version 0.1.3!"
       putPrompt
       mapM_ process . takeWhile (/= "quit\n") . chop =<< getContents
       where process str = putStr str >> putPrompt
             putPrompt = putStr ">>> " >> hFlush stdout

抱歉,它根本不起作用。该死的困惑。

P.S.我想在每个 block 的末尾保留 \n 字符。目前,我在 lines 之后使用 map (++ "\n") 手动添加它们。

最佳答案

稍微改变一下chop的类型怎么样:

readMultiLine :: IO [String]
readMultiLine = do
              ln <- getLine
              if (endswith (rstrip ln) ",") then
                liftM (ln:) readMultiLine
              else
                return [ln]

现在您知道,如果最后一个列表不为空,则用户尚未完成输入(最后一个输入以 ',' 结尾)。

当然,可以导入 Data.String.Utils,或者编写您自己的。可能很简单:

endswith xs ys = (length xs >= length ys)
                 && (and $ zipWith (==) (reverse xs) (reverse ys))
rstrip = reverse . dropWhile isSpace . reverse

但我一开始就没有捕获重点。这就是实际情况。

unfoldM :: (Monad m) => (a -> Maybe (m b, m a)) -> a -> m [b]
unfoldM f z = case f z of
            Nothing -> return []
            Just (x, y) -> liftM2 (:) x $ y >>= unfoldM f

main = unfoldM (\x -> if (x == ["quit"]) then Nothing
                      else Just (print x, readMultiLine)) =<< readMultiLine

原因是,您需要能够在读取一个多行输入和下一个多行输入之间插入要在输入上完成的“操作”。这里 print x 是插入到两个 readMultiLine

之间的操作 <小时/>

既然您对 getContents 有疑问,请让我补充一下。尽管 getContents 提供了惰性 String,但它对世界的有效更改是按照处理列表的后续效果排序的。但是列表的处理尝试在读取特定列表项的效果之间插入效果。为此,您需要一个公开效果链的函数,以便您可以在它们之间插入您自己的效果。

关于haskell - 读取多行用户输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26483920/

相关文章:

c++ - 写入文件时保留空格

c - fgets() 的返回值

c++ - 将 .mat 文件从 MATLAB 转换为 OpenCV 中的 cv::Mat 矩阵

haskell - 如何将函数元组转换为发出元组的函数

haskell - 如何在 Haskell 中重构这段代码

haskell - 如何从 Haskell 中的 fork 进程读取数据?

c++ - std::basic_ifstream 抛出 std::bad_cast

haskell - 为什么 ghci 对类型列表和类型族进行脱糖?可以选择性地禁用它吗?

haskell - 值构造器的别名

time - 需要可以写入流的 Common Lisp 计时函数