IO happens out of order when using getLine and putStr









up vote
22
down vote

favorite
7












I'm a Haskell beginner, I'm just beginning to wrap my head around Monads, but I don't really get it yet. I'm writing a game that consists of asking the user for input, and responding. Here is a simplified version of my function:



getPoint :: IO Point
getPoint = do
putStr "Enter x: "
xStr <- getLine
putStr "Enter y: "
yStr <- getLine
return $ Point (read xStr) (read yStr)


completeUserTurn :: (Board, Player) -> IO (Board, Player)
completeUserTurn (board, player) = do
putStr $ "Enter some value: "
var1 <- getLine
putStr $ "Enter another value: "
var2 <- getLine
putStr $ "Enter a point this time: "
point <- getPoint
if (... the player entered legal values ...) then do
putStr $ "This is what would happen if you did that: stuff do you want to do that? (y/n) "
continue <- getLine
if continue == "y" then
return (...updated board..., ...updated player...)
else
completeUserTurn (board, player)
else do
putStr "Invalid Move!n"
completeUserTurn (board, player)


What's happening is that the prompts will appear out of order with the text that is supposed to appear before the prompt.



Here's an example of what's happening after I compiled the code above:




1

Enter some value: Enter another value:2
3
4

Enter a point this time: Enter x: Enter y: y

Is this correct? (y/n):




The bold are the things I typed in.



Obviously, I have some major conceptual error, but I don't know what. Note that it works correctly in the interpreter and fails when compiled.










share|improve this question



























    up vote
    22
    down vote

    favorite
    7












    I'm a Haskell beginner, I'm just beginning to wrap my head around Monads, but I don't really get it yet. I'm writing a game that consists of asking the user for input, and responding. Here is a simplified version of my function:



    getPoint :: IO Point
    getPoint = do
    putStr "Enter x: "
    xStr <- getLine
    putStr "Enter y: "
    yStr <- getLine
    return $ Point (read xStr) (read yStr)


    completeUserTurn :: (Board, Player) -> IO (Board, Player)
    completeUserTurn (board, player) = do
    putStr $ "Enter some value: "
    var1 <- getLine
    putStr $ "Enter another value: "
    var2 <- getLine
    putStr $ "Enter a point this time: "
    point <- getPoint
    if (... the player entered legal values ...) then do
    putStr $ "This is what would happen if you did that: stuff do you want to do that? (y/n) "
    continue <- getLine
    if continue == "y" then
    return (...updated board..., ...updated player...)
    else
    completeUserTurn (board, player)
    else do
    putStr "Invalid Move!n"
    completeUserTurn (board, player)


    What's happening is that the prompts will appear out of order with the text that is supposed to appear before the prompt.



    Here's an example of what's happening after I compiled the code above:




    1

    Enter some value: Enter another value:2
    3
    4

    Enter a point this time: Enter x: Enter y: y

    Is this correct? (y/n):




    The bold are the things I typed in.



    Obviously, I have some major conceptual error, but I don't know what. Note that it works correctly in the interpreter and fails when compiled.










    share|improve this question

























      up vote
      22
      down vote

      favorite
      7









      up vote
      22
      down vote

      favorite
      7






      7





      I'm a Haskell beginner, I'm just beginning to wrap my head around Monads, but I don't really get it yet. I'm writing a game that consists of asking the user for input, and responding. Here is a simplified version of my function:



      getPoint :: IO Point
      getPoint = do
      putStr "Enter x: "
      xStr <- getLine
      putStr "Enter y: "
      yStr <- getLine
      return $ Point (read xStr) (read yStr)


      completeUserTurn :: (Board, Player) -> IO (Board, Player)
      completeUserTurn (board, player) = do
      putStr $ "Enter some value: "
      var1 <- getLine
      putStr $ "Enter another value: "
      var2 <- getLine
      putStr $ "Enter a point this time: "
      point <- getPoint
      if (... the player entered legal values ...) then do
      putStr $ "This is what would happen if you did that: stuff do you want to do that? (y/n) "
      continue <- getLine
      if continue == "y" then
      return (...updated board..., ...updated player...)
      else
      completeUserTurn (board, player)
      else do
      putStr "Invalid Move!n"
      completeUserTurn (board, player)


      What's happening is that the prompts will appear out of order with the text that is supposed to appear before the prompt.



      Here's an example of what's happening after I compiled the code above:




      1

      Enter some value: Enter another value:2
      3
      4

      Enter a point this time: Enter x: Enter y: y

      Is this correct? (y/n):




      The bold are the things I typed in.



      Obviously, I have some major conceptual error, but I don't know what. Note that it works correctly in the interpreter and fails when compiled.










      share|improve this question















      I'm a Haskell beginner, I'm just beginning to wrap my head around Monads, but I don't really get it yet. I'm writing a game that consists of asking the user for input, and responding. Here is a simplified version of my function:



      getPoint :: IO Point
      getPoint = do
      putStr "Enter x: "
      xStr <- getLine
      putStr "Enter y: "
      yStr <- getLine
      return $ Point (read xStr) (read yStr)


      completeUserTurn :: (Board, Player) -> IO (Board, Player)
      completeUserTurn (board, player) = do
      putStr $ "Enter some value: "
      var1 <- getLine
      putStr $ "Enter another value: "
      var2 <- getLine
      putStr $ "Enter a point this time: "
      point <- getPoint
      if (... the player entered legal values ...) then do
      putStr $ "This is what would happen if you did that: stuff do you want to do that? (y/n) "
      continue <- getLine
      if continue == "y" then
      return (...updated board..., ...updated player...)
      else
      completeUserTurn (board, player)
      else do
      putStr "Invalid Move!n"
      completeUserTurn (board, player)


      What's happening is that the prompts will appear out of order with the text that is supposed to appear before the prompt.



      Here's an example of what's happening after I compiled the code above:




      1

      Enter some value: Enter another value:2
      3
      4

      Enter a point this time: Enter x: Enter y: y

      Is this correct? (y/n):




      The bold are the things I typed in.



      Obviously, I have some major conceptual error, but I don't know what. Note that it works correctly in the interpreter and fails when compiled.







      haskell user-input monads






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Sep 9 '17 at 22:59









      nbro

      5,48484691




      5,48484691










      asked Nov 2 '12 at 6:19









      Drew

      3,40664072




      3,40664072






















          3 Answers
          3






          active

          oldest

          votes

















          up vote
          42
          down vote



          accepted










          As Michael said, the issue is buffering. By default, output is buffered until you print a newline (or until the buffer is full if you have really long lines), so you'll most often see this issue when trying to do same-line prompts using putStr like you're doing.



          I suggest defining a small helper function like this to take care of doing the flushing for you:



          import System.IO

          prompt :: String -> IO String
          prompt text = do
          putStr text
          hFlush stdout
          getLine


          Now you can simply do



          getPoint = do
          xStr <- prompt "Enter x: "
          yStr <- prompt "Enter y: "
          return $ Point (read xStr) (read yStr)





          share|improve this answer
















          • 14




            This is the same behavior as the C stdio library, except that stdio has a hack that I argued Haskell should have as well, namely if you read from stdin then you flush stdout, if both are a tty.
            – augustss
            Nov 2 '12 at 8:23

















          up vote
          13
          down vote













          The IO is happening in the correct order. The issue is buffering. If you flush stdout after each putStr, it should work as expecting. You'll need to import hFlush and stdout from System.IO.






          share|improve this answer



























            up vote
            10
            down vote













            The problem wasn't with the order of operations in the IO code. The issue was input and output is by default buffered when using stdin and stdout. This increases the performance of IO in an app, but can cause operations to appear to occur out of order when both stdin and stdout are used.



            There is two solutions to this. You can use the hFlush method to force a handle (either stdin or stdout) to be flushed. Eg hFlush stdout, hFlush stdin. A simpler solution (which works fine for interactive apps) is to disable buffering altogether. You can do this by calling the methods hSetBuffering stdout NoBuffering and hSetBuffering stdin NoBuffering before you start your program (ie put those lines in your main method.






            share|improve this answer




















              Your Answer






              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "1"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader:
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              ,
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );













               

              draft saved


              draft discarded


















              StackExchange.ready(
              function ()
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f13190314%2fio-happens-out-of-order-when-using-getline-and-putstr%23new-answer', 'question_page');

              );

              Post as a guest















              Required, but never shown

























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              42
              down vote



              accepted










              As Michael said, the issue is buffering. By default, output is buffered until you print a newline (or until the buffer is full if you have really long lines), so you'll most often see this issue when trying to do same-line prompts using putStr like you're doing.



              I suggest defining a small helper function like this to take care of doing the flushing for you:



              import System.IO

              prompt :: String -> IO String
              prompt text = do
              putStr text
              hFlush stdout
              getLine


              Now you can simply do



              getPoint = do
              xStr <- prompt "Enter x: "
              yStr <- prompt "Enter y: "
              return $ Point (read xStr) (read yStr)





              share|improve this answer
















              • 14




                This is the same behavior as the C stdio library, except that stdio has a hack that I argued Haskell should have as well, namely if you read from stdin then you flush stdout, if both are a tty.
                – augustss
                Nov 2 '12 at 8:23














              up vote
              42
              down vote



              accepted










              As Michael said, the issue is buffering. By default, output is buffered until you print a newline (or until the buffer is full if you have really long lines), so you'll most often see this issue when trying to do same-line prompts using putStr like you're doing.



              I suggest defining a small helper function like this to take care of doing the flushing for you:



              import System.IO

              prompt :: String -> IO String
              prompt text = do
              putStr text
              hFlush stdout
              getLine


              Now you can simply do



              getPoint = do
              xStr <- prompt "Enter x: "
              yStr <- prompt "Enter y: "
              return $ Point (read xStr) (read yStr)





              share|improve this answer
















              • 14




                This is the same behavior as the C stdio library, except that stdio has a hack that I argued Haskell should have as well, namely if you read from stdin then you flush stdout, if both are a tty.
                – augustss
                Nov 2 '12 at 8:23












              up vote
              42
              down vote



              accepted







              up vote
              42
              down vote



              accepted






              As Michael said, the issue is buffering. By default, output is buffered until you print a newline (or until the buffer is full if you have really long lines), so you'll most often see this issue when trying to do same-line prompts using putStr like you're doing.



              I suggest defining a small helper function like this to take care of doing the flushing for you:



              import System.IO

              prompt :: String -> IO String
              prompt text = do
              putStr text
              hFlush stdout
              getLine


              Now you can simply do



              getPoint = do
              xStr <- prompt "Enter x: "
              yStr <- prompt "Enter y: "
              return $ Point (read xStr) (read yStr)





              share|improve this answer












              As Michael said, the issue is buffering. By default, output is buffered until you print a newline (or until the buffer is full if you have really long lines), so you'll most often see this issue when trying to do same-line prompts using putStr like you're doing.



              I suggest defining a small helper function like this to take care of doing the flushing for you:



              import System.IO

              prompt :: String -> IO String
              prompt text = do
              putStr text
              hFlush stdout
              getLine


              Now you can simply do



              getPoint = do
              xStr <- prompt "Enter x: "
              yStr <- prompt "Enter y: "
              return $ Point (read xStr) (read yStr)






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Nov 2 '12 at 7:11









              hammar

              124k16261359




              124k16261359







              • 14




                This is the same behavior as the C stdio library, except that stdio has a hack that I argued Haskell should have as well, namely if you read from stdin then you flush stdout, if both are a tty.
                – augustss
                Nov 2 '12 at 8:23












              • 14




                This is the same behavior as the C stdio library, except that stdio has a hack that I argued Haskell should have as well, namely if you read from stdin then you flush stdout, if both are a tty.
                – augustss
                Nov 2 '12 at 8:23







              14




              14




              This is the same behavior as the C stdio library, except that stdio has a hack that I argued Haskell should have as well, namely if you read from stdin then you flush stdout, if both are a tty.
              – augustss
              Nov 2 '12 at 8:23




              This is the same behavior as the C stdio library, except that stdio has a hack that I argued Haskell should have as well, namely if you read from stdin then you flush stdout, if both are a tty.
              – augustss
              Nov 2 '12 at 8:23












              up vote
              13
              down vote













              The IO is happening in the correct order. The issue is buffering. If you flush stdout after each putStr, it should work as expecting. You'll need to import hFlush and stdout from System.IO.






              share|improve this answer
























                up vote
                13
                down vote













                The IO is happening in the correct order. The issue is buffering. If you flush stdout after each putStr, it should work as expecting. You'll need to import hFlush and stdout from System.IO.






                share|improve this answer






















                  up vote
                  13
                  down vote










                  up vote
                  13
                  down vote









                  The IO is happening in the correct order. The issue is buffering. If you flush stdout after each putStr, it should work as expecting. You'll need to import hFlush and stdout from System.IO.






                  share|improve this answer












                  The IO is happening in the correct order. The issue is buffering. If you flush stdout after each putStr, it should work as expecting. You'll need to import hFlush and stdout from System.IO.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 2 '12 at 6:56









                  Michael Snoyman

                  27.5k23466




                  27.5k23466




















                      up vote
                      10
                      down vote













                      The problem wasn't with the order of operations in the IO code. The issue was input and output is by default buffered when using stdin and stdout. This increases the performance of IO in an app, but can cause operations to appear to occur out of order when both stdin and stdout are used.



                      There is two solutions to this. You can use the hFlush method to force a handle (either stdin or stdout) to be flushed. Eg hFlush stdout, hFlush stdin. A simpler solution (which works fine for interactive apps) is to disable buffering altogether. You can do this by calling the methods hSetBuffering stdout NoBuffering and hSetBuffering stdin NoBuffering before you start your program (ie put those lines in your main method.






                      share|improve this answer
























                        up vote
                        10
                        down vote













                        The problem wasn't with the order of operations in the IO code. The issue was input and output is by default buffered when using stdin and stdout. This increases the performance of IO in an app, but can cause operations to appear to occur out of order when both stdin and stdout are used.



                        There is two solutions to this. You can use the hFlush method to force a handle (either stdin or stdout) to be flushed. Eg hFlush stdout, hFlush stdin. A simpler solution (which works fine for interactive apps) is to disable buffering altogether. You can do this by calling the methods hSetBuffering stdout NoBuffering and hSetBuffering stdin NoBuffering before you start your program (ie put those lines in your main method.






                        share|improve this answer






















                          up vote
                          10
                          down vote










                          up vote
                          10
                          down vote









                          The problem wasn't with the order of operations in the IO code. The issue was input and output is by default buffered when using stdin and stdout. This increases the performance of IO in an app, but can cause operations to appear to occur out of order when both stdin and stdout are used.



                          There is two solutions to this. You can use the hFlush method to force a handle (either stdin or stdout) to be flushed. Eg hFlush stdout, hFlush stdin. A simpler solution (which works fine for interactive apps) is to disable buffering altogether. You can do this by calling the methods hSetBuffering stdout NoBuffering and hSetBuffering stdin NoBuffering before you start your program (ie put those lines in your main method.






                          share|improve this answer












                          The problem wasn't with the order of operations in the IO code. The issue was input and output is by default buffered when using stdin and stdout. This increases the performance of IO in an app, but can cause operations to appear to occur out of order when both stdin and stdout are used.



                          There is two solutions to this. You can use the hFlush method to force a handle (either stdin or stdout) to be flushed. Eg hFlush stdout, hFlush stdin. A simpler solution (which works fine for interactive apps) is to disable buffering altogether. You can do this by calling the methods hSetBuffering stdout NoBuffering and hSetBuffering stdin NoBuffering before you start your program (ie put those lines in your main method.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 2 '12 at 7:07









                          David Miani

                          12.9k13660




                          12.9k13660



























                               

                              draft saved


                              draft discarded















































                               


                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f13190314%2fio-happens-out-of-order-when-using-getline-and-putstr%23new-answer', 'question_page');

                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Top Tejano songwriter Luis Silva dead of heart attack at 64

                              政党

                              天津地下鉄3号線