简体   繁体   English

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

[英]Haskell IO create a list of strings and display it

I'm trying to write a program that allows the user to build up a list of strings by entering them in one at a time, and displays the list after every step. 我正在尝试编写一个程序,允许用户通过一次输入一个字符串来建立字符串列表,并在每个步骤后显示列表。

Here is my code so far: 到目前为止,这是我的代码:

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 is starting the list by passing in the empty list, and I'm trying to use recursion so that the code keeps running until the user enters the empty string. listBuilder通过传入空列表来启动列表,我正在尝试使用递归,以便代码一直运行,直到用户输入空字符串。

Its not working, any ideas welcome 它没有用,欢迎任何想法

Here is a desired input: 这是一个理想的输入:

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

Error: 错误:

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

EDIT: 编辑:

This fixed it, thanks to the clues and use of show 由于线索和使用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 []

You can get this working by 你可以通过这个工作

(a) putting the new string at the end of the list with arr++[str] instead of arr:str since : can only be used like singleThing:list , (a)使用arr++[str]而不是arr:str将新字符串放在列表的末尾,因为:只能像singleThing:list一样使用,
(b) splitting the run-round into a separate function, and (b)将跑动分为单独的功能,和
(c) passing the result on with return so you can use it elsewhere in your program (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

giving

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

done

You can solve this problem more declaratively using the pipes and foldl libraries: 您可以使用pipesfoldl库以声明方式解决此问题:

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

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

You can read this as a pipeline: 您可以将其读作管道:

  • P.stdinLn is a source of lines input by the user P.stdinLn是用户输入的行的源

  • P.scan behaves like Data.List.scanl , except for pipelines instead of lists. P.scan行为类似于Data.List.scanl ,管道而不是列表除外。 purely P.scan list says to continuously output the values seen so far. purely P.scan list表示要连续输出到目前为止看到的值。

  • P.print prints these output lists to the console P.print这些输出列表打印到控制台

Here's an example of this pipeline in action: 以下是此管道的实例示例:

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

You can also easily switch out other ways to fold the lines just by changing the argument to purely scan . 您也可以通过将参数更改为purely scan来轻松切换折叠线的其他方法。 For example, if you switch out list with Control.Foldl.vector then it will output vectors of lines instead of lists. 例如,如果使用Control.Foldl.vector切换list ,则它将输出行而不是列表的向量。

To learn more, you can read the documentation for the pipes and foldl libraries. 要了解更多信息,您可以阅读管道foldl库的文档。

The problem is that the : data constructor can only be used to append an element to the beginning of the list. 问题是: data构造函数只能用于将元素追加到列表的开头。 When you write let arr=arr:str , you are using it to put an element at the end of the list. 当您编写let arr=arr:str ,您正在使用它将元素放在列表的末尾。 Instead, you can either construct your list backwards like this let arr=str:arr or use the ++ operator to append it to the end of the list like this let arr=arr++[str] . 相反,你可以向后构造你的列表,像这样let arr=str:arr或使用++运算符将它附加到列表的末尾,就像这样let arr=arr++[str]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM