无法同时接收2个输入

时间:2012-07-14 13:08:20

标签: haskell getline

我是一名哈斯克尔初学者。我的代码:

module Main (main) where

import System.IO

--Type for identifying Students.
data Student = Student {
        name :: String,
        regnum :: Integer
    }   deriving (Show, Read)

getData :: IO (String)
getData = do
    putStr "\tEnter the student's name: "
    name <- getLine
    putStr "\tEnter the registration number: "
    regstr <- getLine
    let regno = (read regstr) :: Integer
    return (show ( Student name regno ))

addData :: String -> IO (Bool)
addData filename = do
    fileData <- getData
    appendFile filename fileData
    return True

printData :: String -> IO (Bool)
printData filename = do
    fileData <- readFile filename
    putStrLn fileData
    return True

resetFile :: String -> IO (Bool)
resetFile filename = writeFile filename "" >> return True

action :: Char -> String -> IO (Bool)
action option filename =
    if option == '1'
        then addData filename
    else if option == '2'
        then printData filename
    else if option == '3'
        then resetFile filename
    else return False

main = do 
        putStr "What do you want to do?\n\t1) Add a new record to a file.\n\t2) Read a record from a file.\n\t3) Reset the file.\n>> "
        option <- getChar
        action option "records.txt"

我得到的输出是:

What do you want to do?
    1) Add a new record to a file.
    2) Read a record from a file.
    3) Reset the file.
>> 1
    Enter the student's name:   Enter the registration number: 

因此我无法为学生的姓名提供输入。我在 ghci 上运行代码。当我试图看它如何作为可执行文件运行时,它给出了更奇怪的输出。

What do you want to do?
    1) Add a new record to a file.
    2) Read a record from a file.
    3) Reset the file.

(请注意,它不会打印“&gt;&gt;”)。只有在我按两次Enter后才打印“&gt;&gt;”。 我无法理解这里发生了什么。我的代码的其他改进非常受欢迎。


编辑::通过使用getLine而不是getChar,该程序适用于ghci(感谢Daniel Fischer)。但是在编译时它仍然不起作用。新输出是:

What do you want to do?
    1) Add a new record to a file.
    2) Read a record from a file.
    3) Reset the file.
1   (Typed my me)
Tom (Typed my me)
234 (Typed my me)
>> Enter the student's name: Enter the registration number:

重新运行以读取文件:

What do you want to do?
    1) Add a new record to a file.
    2) Read a record from a file.
    3) Reset the file.
2   (Typed my me)
>> Student {name = "Tom", regnum = 234}

为什么“&gt;&gt;”并且在获取输入后打印getData的putStr

1 个答案:

答案 0 :(得分:4)

option <- getChar

使用默认缓冲设置,程序仅在输入换行符后才接收输入。但是,getChar仅删除从输入缓冲区输入的第一个字符,因此以下getLine从输入缓冲区中读取,直到找到换行符。在你的情况下,立即开始。

你可以(至少在* nix-ish系统上,缓冲控制用于在Windows上无法正常工作,我不知道它现在是否可以)通过关闭stdin的缓冲来解决问题,< / p>

main = do
    hSetBuffering stdin NoBuffering
    ...

所以getChar收到输入而没有输入换行符。或者,不要使用getChar作为选项,而是使用

(option:_) <- getLine

因此输入缓冲区中没有任何内容可以自动满足以下getLine

此外,要在输入输入之前输出提示,请致电

hFlush stdout

刷新输出缓冲区,或关闭stdout的缓冲。

最简单的可能是定义

prompt :: String -> IO ()
prompt msg = do
    putStr msg
    hFlush stdout

并通过调用putStr替换对prompt的来电。


对编码风格的批判:

getData :: IO (String)

IO类型构造函数的参数括在括号中。这不是必要和单一的。写它的正常方法是IO String。 (你可能在某处看到IO ()的括号,但那些不是括号的括号,那是()类型的类型构造函数。令人困惑?是的。)

action :: Char -> String -> IO (Bool)
action option filename =
    if option == '1'
        then addData filename
    else if option == '2'
        then printData filename
    else if option == '3'
        then resetFile filename
    else return False

应该成为case

action option filename
    = case option of
        '1' -> addData filename
        '2' -> printData filename
        '3' -> resetFile filename
        _   -> return False

除此之外,代码看起来很干净。