/ / Как да чета и обработва потребителско въвеждане безкрайно в Haskell - haskell

Как да четем и обработваме безкрайно потребителски вход в Haskell - haskell

Бих искал моята командна линия Haskell да функционира така: програма изчакване за въвеждане от потребителя,

  1. потребител въведете нещо, натиснете „въведете“
  2. Haskell обработва входа, показва резултата при stdout
  3. Haskell изчаква следващия потребителски вход
  4. Ако няма повече вход, потребителят прекратява програмата от Ctrl + D

Опитах getContents. Но getContents изчакват потребителят да въведе всички линии, преди да ги обработи.

Отговори:

7 за отговор № 1

Тук се случва много объркване. Нека се опитаме да изясним нещата.

Опитах getContents. Но getContents изчакват потребителят да въведе всички линии, преди да ги обработи.

Най-вероятно тук е, че сте компилирали програмата си и не забелязахте, че буферирането по подразбиране за изход е буфериране на блок. Това е лесно да се поправи:

f line = putStrLn ("Hi, " ++ line ++ "!")

main = do
hSetBuffering stdout LineBuffering -- or use NoBuffering
putStrLn "Enter some names."
input <- getContents
mapM_ f (lines input)

Трябва да използвате NoBuffering ако не планирате да отпечатвате цяла линия (включително нова линия) след всеки ред от въвеждане на потребител.

За по-точен отговор ще трябва да видим кода, който сте опитвали, че не работи.

В: Но в първия си опит използвам: „взаимодействащо шоу“ и това не работи. Знаете ли защо?
A: Защото шоуто няма да върне никакъв изход, докато целият му вход не бъде изчерпан.

Този отговор не е съвсем правилен. Истинският отговор е този show създава низ, в който няма нови редове! (Макар че последователността на знаците ["\","n"] прави показват се понякога, ако входът е дълъг повече от един ред.) И така, за interact show, наистина трябва да използвате NoBuffering за stdout, Например, ако използвате това:

main = do
hSetBuffering stdout NoBuffering
interact show

... програмата ще отпечата малко повече резултати след всеки ред. Може също да искате да зададете stdinбуфериране към NoBuffering (вместо по подразбиране LineBuffering), от show е достатъчно продуктивен, че наистина може да доведе до повече резултати след всеки натискане на клавиш.


6 за отговор № 2

Можете да опитате да използвате interact функция. Той отнема функция от типа String -> String и го превръща в действие, което чете stdin,предава го непрекъснато към функцията и записва низа, който функцията връща към stdout. Ако се грижите да не прекалявате с въвеждащия низ, ще получите поведението, което сте поискали.


5 за отговор № 3

употреба isEOF и getLine за четене на вход.

По този начин се избягват мързеливите i / o проблеми, които сте използвали interact.

(Ако не използваме isEOF, изключение ще бъде хвърлено, когато натиснем Ctrl + D.)

import Control.Monad (unless)
import System.IO (isEOF)

processEachLine :: (String -> IO a) -> IO ()
processEachLine k = do
finished <- isEOF
unless finished $ do
k =<< getLine
processEachLine k

Тук допускам, че k функция отпечатва необходимия изход. Лесно се променя processEachLine да отпечатате изхода, така че k може да бъде чист.