Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected behavior, with effects on stdin/out not running #153

Closed
freckletonj opened this issue Dec 6, 2020 · 2 comments
Closed

Unexpected behavior, with effects on stdin/out not running #153

freckletonj opened this issue Dec 6, 2020 · 2 comments

Comments

@freckletonj
Copy link
Contributor

freckletonj commented Dec 6, 2020

I've spent some time boiling this bug (?) down to a simple example:

  1. readLn
  2. (*100)
  3. print
input :: ClSF IO StdinClock () Int
input = arrMCl (const $ fromMaybe 0 . readMaybe <$> getLine)

stepFn :: Monad m => ClSF m (Millisecond 300) Int Int
stepFn = arr (*100)

output :: Show a => ClSF IO (Millisecond 500) a ()
output = arrMCl print

main :: IO ()
main = flow $
  (input @@ StdinClock)
  >-- (keepLast 1 -@- concurrently) -->
  (stepFn @@ waitClock)
  >-- (collect -@- concurrently) -->
  (output @@ waitClock)

When I run this, it starts printing as expected.

Then I enter a number at the repl, and printing stops.

If I enter numbers 4 times printing continues, but the interim 3 numbers fall into a black hole, never getting processed.

Enter a 5th number, and printing stops again, until you've entered 4 more numbers.

Each time you get printing to resume, it catch-up-prints dozens of numbers, but they'll all be the most recently input number, many times all instantaneously.

EDIT: I thought it was a flushing issue, but nope, that number never gets processed, as evident in the "catchup" prints. I've even tried passing stdin/out handles throughout and manually flushing, and... no go.

EDIT: Doesn't help to print to stderr, nor to change the buffering status of the handle (hSetBuffering stdin NoBuffering). Probably just spinning my wheels at this point 😅

EDIT: Let me know if you struggle to reproduce it, I can screencast a video.

@turion
Copy link
Owner

turion commented Dec 6, 2020

This is to be expected, in fact. I ought to document this better. Maybe a FAQ section in the README.md, or what do you think?

The reason is that you have a blocking ClSF, namely input, in the signal network. All purely data-related components should be non-blocking, only clocks are allowed to block. There is no obvious way to prevent blocking IO.

We can simplify your program to make it work. The standard approach to deal with blocking IO is to put it in a clock. In the case of stdin, this has already been done in form of the StdinClock, as you've found out. Since the clock already does the blocking IO, you don't need to do it again with getLine. Instead, you can simply use tagS to retrieve the input line. It should look something like:

input :: ClSF IO StdinClock () Int
input = tagS >-> arr (readMaybe >>> fromMaybe 0)

(You can use >>> instead of >-> as well, matter of taste)

@freckletonj
Copy link
Contributor Author

put blocking code in a clock

ohhh, that makes so much more sense and works perfectly. I'll add a couple of my recent questions and your answers to a FAQ sometime today :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants