Closed thalesmg closed 3 years ago
Yeah, that one is easy 😄 Something like:
timeoutWidget = do
text "1" <|> liftIO (threadDelay 1000000)
text "2" <|> liftIO (threadDelay 1000000)
text "3" <|> liftIO (threadDelay 1000000)
should do the trick. Or even:
timeoutWidget2 = do
div [] [ text "1", liftIO (threadDelay 1000000) ]
div [] [ text "2", liftIO (threadDelay 1000000) ]
div [] [ text "3", liftIO (threadDelay 1000000) ]
(Beware of type errors, code is untested).
Cheers!
Wow, I didn't notice that threadDelay
could be simply lifted like this! Thanks! :beers:
But I tried the following code:
clock = forever $ do
now <- liftIO getCurrentTime
div [] [text . T.pack . show $ now, liftIO $ threadDelay 1000000]
text "other text" <|> liftIO (threadDelay 3000000)
It does print out the current time for 1 second (but not other text
), then it prints other text
and the time disappears, then everything disappears.
Due to forever
, shouldn't it keep rendering at least the time and other text
loop?
EDIT: I've just tried another variation:
clock = forever $ do
now <- liftIO getCurrentTime
div [] [text . T.pack . show $ now, liftIO . forever $ threadDelay 1000000]
text "other text" <|> liftIO (forever $ threadDelay 3000000)
This time, the text stays rendered on the page, but the current time is never recomputed and other text
never shows up.
By the way, your example works fine: it prints 1
, 2
, 3
and then stops. If I add forever
or simply recurse, it prints the numbers in a loop.
I'm still trying to figure out how is this working and why other text
from my example never prints out. :thinking:
I got the clock example working, despite not understanding why there can't be more elements after the timeout one :stuck_out_tongue_closed_eyes:
clock = do
now' <- liftIO getCurrentTime
div [] [text . T.pack . show $ now', liftIO $ threadDelay 1000000]
clock
This one updates the time each second, as long as I don't add any other elements after the div
.
Interesting, your clock example with forever
works here, see attached video.
I suspect the explanation is that concur
has some concurrency bugs still, which I haven't had the time to fix. Unfortunately, due the nature of the concur
model it's not that easy to get everything right, so this will take time :(
I wouldn't recommend using it in production.
I see! Maybe it is something platform dependent? I'm using Linux, and you seem to be using MacOS.
I wouldn't recommend using it in production.
I was just trying it for a small personal project. I found it while researching for Phoenix LiveView alternatives. =)
I'm having trouble trying to understand concur
's Widget/Free (SuspendF v) a
type and how it all wires up together, it seems very complex (without many comments to help :sweat_smile: ).
I managed to make some text appear after the clock, but not sure why the second version works and the first doesn't:
clock = do
now' <- liftIO getCurrentTime
div [] [(text . T.pack . show $ now') <|> liftIO (threadDelay 1000000)]
clock
-- This does not print the text after the clock
clockAndStuff = do
div [] [clock]
p [] [text "I should print!"]
-- This prints the text after the clock
clockAndStuff2 = do
div [] [clock, p [] [text "I should print!"]]
Anyway, thanks a lot for the help!! I can continua playing with the lib now! Cheers! :beers:
I'm having trouble trying to understand concur's
Widget/Free (SuspendF v) a
It's a bit convoluted, but the basic idea is to describe an UI in terms of "show a view" and "block on IO" steps, then the concur
magic (e.g. executing Widget
s in parallel and killing all siblings when a Widget
ends) happens in orr
:)
Your examples work as intended:
clockAndStuff = do
div [] [clock]
p [] [text "I should print!"]
Here, clock
never ends, so div [] [clock]
never ends and p [] [text "I should print!"]
is never reached. On the other hand:
clockAndStuff2 = do
div [] [clock, p [] [text "I should print!"]]
Here you're displaying the clock
and text
in parallel, so both show at the same time. Hope this helps 👍
It does help! Thanks for the explanation!! =)
I'll still need to pour some thinking into the whole thing :see_no_evil: , but now I see why each example behaves differently.
As a small complementary question, what is the difference between StepBlock
and StepIO
?
They both have the same structure:
| forall r. StepBlock (IO r) (r -> next)
| forall r. StepIO (IO r) (r -> next)
But, inspecting stepW
, it seems that the purpose of StepIO
is to execute the longest sequence of IO actions queued up, while StepBlock
seems to execute the single next IO action and then immediatly yield a view plus the suspened state:
stepW :: v -> Free (SuspendF v) a -> IO (Either a (v, Maybe (Either (STM (Free (SuspendF v) a)) (IO (Free (SuspendF v) a)))))
stepW _ (Free (StepView v next)) = stepW v next
stepW v (Free (StepIO a next)) = a >>= stepW v . next
stepW v (Free (StepBlock a next)) = pure $ Right (v, Just $ Right (a >>= pure . next))
stepW v (Free (StepSTM a next)) = pure $ Right (v, Just $ Left (a >>= pure . next))
stepW v (Free Forever) = pure $ Right (v, Nothing)
stepW _ (Pure a) = pure $ Left a
Is this understanding correct?
Cheers!
Your understanding is indeed correct!
StepIO
is used for "non-blocking" IO actions, e.g. thinks like newIORef
, which don't yield a view and don't need to wait on an outside action to unblock. On the other hand, StepBlock
is used for blocking IO (threadDelay
, or user events, like mouse clicks or key presses), and indeed liftIO
lifts an IO action into StepBlock
, because we don't have any guarantee that that action is non-blocking.
Think of StepIO
as an optimisation more than anything else.
Since you're showing interest in Concur, make sure to check out the original framework (created by @ajnsit) here: https://github.com/ajnsit/concur, and its documentation site, which has a really well written and thorough introduction to Concur's mode:l https://github.com/ajnsit/concur-documentation/blob/master/README.md.
Cool! Thanks for all the explanations and for the references! I'll check those docs out! :tropical_drink:
Hello!
First, thanks for this awesome lib!! :beers:
I was wondering: how one could update some widget based on a timeout? For example, if one is trying to make a clock widget, or simply refresh the widget contents periodically?
I was considering, as a workaround, to (somehow) use
setInterval
to set up a timer that would periodically trigger a custom event on the given element. I'd still have to figure out how to add the required javascript to the page, and also how to reference the widget (byid
, probably).Is there some easier and/or more idiomatic way to trigger time based events on
concur-replica
?Cheers