2014-02-14 3 views
2

Я пытаюсь написать программу, которая позволяет пользователю создавать список строк, введя их по одному за раз и отображает список после каждого шага.Haskell 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 

EDIT:

Это зафиксировал его, благодаря ссылки и использование 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 [] 
+1

Это не только не работает, но и не компилируется **. Вы почти получили это; Мое предложение было бы переименовать второй 'arr' в нечто вроде' newarr' или 'arr'', чтобы избежать путаницы и конфликтов имен. –

+0

это правильно, я совсем застрял! – benharris

+1

Снова прочитайте ошибку компилятора. Он пытается вам помочь. Во всяком случае, мне потребовалось несколько незначительных исправлений, чтобы заставить его работать, поэтому я оставлю его как упражнение. Отправьте ответ, когда вы закончите ':)' –

ответ

3

Вы можете получить эту работу по

(а) поставить новую строку в конце списка с arr++[str] вместо arr:str после : может быть использован только как singleThing:list,
(б) разделение вводного круглый в отдельную функцию, и
(с) передавая результат на с 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 
+0

Не забудьте проверить [ответ Габриэля Гонсалеса] (http://stackoverflow.com/a/21792654/1598537); это очень ценно для изучения труб, и здесь так же хорошо, как и любой другой, - вы поразили золото, получив ответ от одного из ведущих огней Хаскелла. – AndrewC

2

Проблемы заключается в том, что конструктор : данных может быть использован только для добавления элемента в начало списка. Когда вы пишете let arr=arr:str, вы используете его, чтобы поместить элемент в конец списка. Вместо этого вы можете либо построить свой список назад, как этот let arr=str:arr, либо использовать оператор ++, чтобы добавить его в конец списка наподобие этого let arr=arr++[str].

3

Вы можете решить эту проблему более декларативно, используя pipes и foldl библиотеки:

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, за исключением pipeli nes вместо списков. 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, тогда он будет выводить векторы строк вместо списков.

Чтобы узнать больше, вы можете ознакомиться с документацией для библиотек pipes и foldl.

+0

Вы имели в виду 'Data.List.scanl1', возможно? –

+0

Да, я имел в виду 'scanl' (нет 1). Я исправлю это. –