简体   繁体   中英

How to add to a List from IO in Haskell.

I am trying to write a simple function which reads in one line at a time (which I know will be integers) and then stores them in to a list. For the life of me however, it seems like the list comes out to empty.

import System.IO
import Control.Monad

type Int2 = [Int]

valueTab = [] :: [Int]

app [ ] list = list 
app (h:t) list = h:(app t list)

main :: IO ()
main = do
    hSetBuffering stdout NoBuffering -- DO NOT REMOVE

    -- Auto-generated code below aims at helping you parse
    -- the standard input according to the problem statement.

    input_line <- getLine
    let n = read input_line :: Int
    let value = [] :: [Int]

    replicateM n $ do
        input_line <- getLine
        let pi = read input_line :: Int
        hPutStrLn stderr (show input_line)
        hPutStrLn stderr (show valueTab)
        return $ app valueTab [pi]


    -- hPutStrLn stderr "Debug messages..."

    -- Write answer to stdout


    --putStrLn input_line
    return ()

So when I run this with 8 6 4 3 all on their own lines, It prints 6, [], 4, [], 3 [].

Is this a problem with my printing, with my list declaration, with the way that I store them or? I have both value and valueTab to check whether it was a scope problem.

Note: The code is boilerplate code on a coding website that tests it on it's platform. Assume replicateM is just a loop that runs through the code x number of times.

It looks like you're doing a problem on codinggame.com. Other coding sites seem to do a better job with their Haskell templates, particularly for beginner exercises -- the template usually takes care of all the input and output, and you just need to supply the missing pure function. In contrast, codinggame.com's Haskell templates seem to assume the beginner has a pretty firm grasp of the IO monad, and leave out a lot of essential details (eg, the fact that the result of the replicateM action should actually be bound to a variable) which you're expected to fill in.

The replicateM call in the original template probably looked something like:

replicateM n $ do
    input_line <- getLine
    let pi = read input_line :: Int    -- maybe this line was there, maybe not
    return ()

This expression creates a composite IO action that, when executed, will repeat the following subaction n times:

  • read a line, binding the string read to input_line
  • prepare to convert that line to an integer value pi (though this is never done because pi isn't used)
  • regardless of the string read, return "unit" (the value () ) as the result of the subaction

The value of the composite action is then a list of the values returned by the subactions. Since those were all units, the final value of the composite action is a list [(),(),()...()] , with one () for each line read. However, because the value of this composite action is never bound to a variable (ie, because there's no result <- ... before the replicateM expression), this list is thrown away.

So, this template provides a needlessly verbose method of reading n lines of input and doing nothing with them.

Fortunately, all you need to do to make this template do something useful is to have the subaction return a value that's useful (eg, the integer pi ) which will cause the composite action to return a list of the integers read, and then make sure you bind the resulting list to a variable using the <- notation.

In other words, you want to write:

main = do
    ...

    pis <- replicateM n $ do
        input_line <- getLine
        let pi = read input_line :: Int
        return pi

    hPutStrLn stderr (show pis)

You won't need the helper function app , and you won't need to pre-declare a list valueTab to contain the result. The result is automatically produced by replicateM , and you just need to name it so you can use it.

The complete working program will look like:

import System.IO
import Control.Monad

type Int2 = [Int]

main :: IO ()
main = do
    hSetBuffering stdout NoBuffering -- DO NOT REMOVE

    -- Auto-generated code below aims at helping you parse
    -- the standard input according to the problem statement.

    input_line <- getLine
    let n = read input_line :: Int
    let value = [] :: [Int]

    pis <- replicateM n $ do
        input_line <- getLine
        let pi = read input_line :: Int
        return pi

    hPutStrLn stderr (show pis)

    -- hPutStrLn stderr "Debug messages..."
    -- Write answer to stdout

    return ()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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