Haskell IO创建一个字符串列表并显示它

时间:2014-02-14 14:57:21

标签: list haskell recursion io

我正在尝试编写一个程序,允许用户通过一次输入一个字符串来建立字符串列表,并在每个步骤后显示列表。

到目前为止,这是我的代码:

buildList :: [String] -> IO ()
buildList arr = do
    putStr "Enter a line:"
    str <- getLine
    if str == "" then
        return ()
    else do
        let newarr = arr : str
        putStrLn ("List is now: " ++ newarr)
        buildList newarr


listBuilder :: IO ()
listBuilder = do
    buildList []

listBuilder通过传入空列表来启动列表,我正在尝试使用递归,以便代码一直运行,直到用户输入空字符串。

它不起作用,欢迎任何想法

这是一个理想的输入:

Enter a line: hello
List is now ["hello"]
Enter a line: world
List is now ["hello","world"]
Enter a line:

错误:

Couldn't match type `Char' with `[String]'
Expected type: [[String]]
  Actual type: String
In the second argument of `(:)', namely `str'
In the expression: arr : str
In an equation for `newarr': newarr = arr : str

编辑:

由于show

的线索和使用,这解决了这个问题
buildList :: [String] -> IO ()
buildList arr = do
    putStr "Enter a line:"
    str <- getLine
    if str == "" then
        return ()
    else do
        let newarr = arr++[str]
        putStrLn ("List is now: " ++ show newarr)
        buildList newarr


listBuilder :: IO ()
listBuilder = do
    buildList []

3 个答案:

答案 0 :(得分:3)

你可以通过

来解决这个问题

(a)将新字符串放在列表末尾,而arr++[str]代替arr:str,因为:只能像singleThing:list一样使用,  (b)将跑动分为单独的功能,和
 (c)将结果传递给return,以便您可以在程序的其他地方使用它

buildList arr = do
    putStrLn "Enter a line:"
    str <- getLine
    if str == "" then
        return arr
    else do
        tell (arr++[str])

tell arr = do
        putStrLn ("List is now: " ++ show arr) -- show arr to make it a String
        buildList arr

Enter a line:
Hello
List is now: ["Hello"]
Enter a line:
world
List is now: ["Hello","world"]
Enter a line:

done

答案 1 :(得分:3)

您可以使用pipesfoldl库以声明方式解决此问题:

import Control.Foldl (purely, list)
import Pipes
import qualified Pipes.Prelude as P

main = runEffect $ P.stdinLn >-> purely P.scan list >-> P.print

您可以将其视为管道:

  • P.stdinLn是用户输入的行的来源

  • P.scan的行为与Data.List.scanl相似,但管道而不是列表除外。 purely P.scan list表示要不断输出到目前为止看到的值。

  • P.print将这些输出列表打印到控制台

以下是此管道的实例示例:

$ ./example
[]
Test<Enter>
["Test"]
ABC<Enter>
["Test","ABC"]
42<Enter>
["Test","ABC","42"]
<Ctrl-D>
$

只需将参数更改为purely scan,您也可以轻松切换其他折叠线的方法。例如,如果您使用list切换Control.Foldl.vector,那么它将输出行的向量而不是列表。

要了解详情,您可以阅读pipesfoldl图书馆的文档。

答案 2 :(得分:2)

问题是:数据构造函数只能用于将元素追加到列表的开头。当您编写let arr=arr:str时,您正在使用它将元素放在列表的末尾。相反,您可以像let arr=str:arr那样向后构建列表,也可以使用++运算符将其附加到列表的末尾,如let arr=arr++[str]