agocorona / hplayground

Translate your console applications to run in the web browser and have reactive, window-oriented and spreadsheet effects for free. Widget combinators running in the browser with the Haste compiler
Other
60 stars 7 forks source link

Question, is custom timeout valid #7

Open NCrashed opened 9 years ago

NCrashed commented 9 years ago

I wasn't able find function that executes Widget a after some time, and implemented it by myself:

timeoutStore :: IORef [String] 
timeoutStore = unsafePerformIO $ newIORef []

storeTimeout :: String -> IO ()
storeTimeout ids = do
  idss <- readIORef timeoutStore
  writeIORef timeoutStore $ ids : idss

removeTimeout :: String -> IO ()
removeTimeout ids = do
  idss <- readIORef timeoutStore
  writeIORef timeoutStore $ filter (/= ids) idss

hasTimeout :: String -> IO Bool
hasTimeout ids = elem ids <$> readIORef timeoutStore

peekTimeout :: String -> Widget () 
peekTimeout ids = do 
  idss <- liftIO $ readIORef timeoutStore
  case ids `elem` idss of 
    True -> noWidget 
    False -> return ()

timeout :: Int -> Widget a -> Widget a
timeout mss wa = do 
  id <- genNewId
  liftIO $ storeTimeout id

  cont <- getCont
  ht <- liftIO $ hasTimeout id
  when ht $ setTimeout mss $ do
    removeTimeout id
    runCont cont

  peekTimeout id 
  wa

Is this idiomatic way to implement the stuff?

agocorona commented 9 years ago

It is a good exercise, and you get it right, but I don´t know why you store timeouts and retrieve them. Why not just execute the timeout?

There is wtimeout in Haste.HPlay.View that executes the widget and repeat it after a timeout. If it does validates, that's all. if not it repeat again:

-- | executes a widget each t milliseconds until it validates and return ()
wtimeout :: Int -> Widget () -> Widget ()
wtimeout t w= View $ do
    id <- genNewId
    let f= setTimeout t $ do
        me <- elemById  id
        case me of
         Nothing -> return ()
         Just e ->do
            r <- clearChildren e >> runWidget w e
            case r of
              Nothing -> f
              Just ()  -> return ()

    liftIO  f
    runView $ identified id w

The last sentence executes the widget immediately. If you remove it, it would execute it only after the timeout.

It seems that you want to de-invert the call. wtimeout does not invert the javascript call since it is inherently asynchronous. Note that you execute the continuation , that is, the rest of the monadic computation when the timeout arrives, and after that, you execute the widget passed as parameter. Is that what you intended to do? The de-inverted call , as I see it, would not have wa parameter, it would only execute the continuation after the timeout...

NCrashed commented 9 years ago

I just need timeout that returns Widget a not Widget (). My widget calculates new model state and wtimeout isn't enough.

It seems that you want to de-invert the call. wtimeout does not invert the javascript call since it is inherently asynchronous. Note that you execute the continuation , that is, the rest of the monadic computation when the timeout arrives, and after that, you execute the widget passed as parameter. Is that what you intended to do?

Yep, that is what I exactly want. I want to force computation after the timeout fires. Example of usage:

myWidget :: State -> Widget State
myWidget state = do
 -- some render
 newState <- timeout 1000 $ calculateNewState state
 return newState

myWidgetLoop :: State -> Widget State
myWidgetLoop initialState = myWidget initialState `wcallback` myWidgetLoop
-- I don't like the implementation as there are growing amount of spans included in each other

but I don´t know why you store timeouts and retrieve them. Why not just execute the timeout?

The idea is that first execution of the function fails due of peekTimeout id, and setTimeout callback opents the "gate" for second pass. I don't know how to implement that without storing tags, unless there are exist continuations in future (to run code after the gate).

NCrashed commented 9 years ago

Hey, I just find out how to loop custom state in widget (with wcallback there was "span leak", each iteration creates new span in old iteration span):

wloop :: a -> (a -> Widget a) -> Widget ()
wloop initialState wa = View $ do
  nid <- genNewId

  FormElm form mx <- runView $ go nid initialState 

  return $ FormElm ((Haste.Perch.span ! atr "id" nid $ noHtml) <> form) mx
  where
    go nid state = do 
      nextState <- at nid Insert (wa state)
      go nid nextState

Usecase:

runApplication :: ApplicationState -> Widget ()
runApplication state = wloop state go
  where 
    go :: ApplicationState -> Widget ApplicationState
agocorona commented 9 years ago

Hi Anton,

Can this be used instead of wcallback?

the signature is slightly different

2015-04-07 23:41 GMT+02:00 Anton Gushcha notifications@github.com:

Hey, I just find out how to loop custom state in widget (with wcallback there was "span leak", each iteration creates new span in old iteration span):

wloop :: a -> (a -> Widget a) -> Widget () wloop initialState wa = View $ do nid <- genNewId

FormElm form mx <- runView $ go nid initialState

return $ FormElm ((Haste.Perch.span ! atr "id" nid $ noHtml) <> form) mx where go nid state = do nextState <- at nid Insert (wa state) go nid nextState

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-90740298.

Alberto.

agocorona commented 9 years ago

the old version that run in tryplayg.herokuapp.com produces a lot of extra spans. please use the new one (use the docker image)

Why not

myWidget :: State -> Widget State myWidget state = do -- some render

timeout 1000

calculateNewState state

don´t pass a seconf parameter. and make calcuateNewState as part of the continuation...

2015-04-07 13:09 GMT+02:00 Anton Gushcha notifications@github.com:

I just need timeout that returns Widget a not Widget (). My widget calculates new model state and wtimeout isn't enough.

It seems that you want to de-invert the call. wtimeout does not invert the javascript call since it is inherently asynchronous. Note that you execute the continuation , that is, the rest of the monadic computation when the timeout arrives, and after that, you execute the widget passed as parameter. Is that what you intended to do?

Yep, that is what I exactly want. I want to force computation after the timeout fires. Example of usage:

myWidget :: State -> Widget State myWidget state = do -- some render newState <- timeout 1000 $ calculateNewState state return newState myWidgetLoop :: State -> Widget State myWidgetLoop initialState = myWidget initialState wcallback myWidgetLoop-- I don't like the implementation as there are growing amount of spans included in each other

but I don´t know why you store timeouts and retrieve them. Why not just execute the timeout?

The idea is that first execution of the function fails due of peekTimeout id, and setTimeout callback opents the "gate" for second pass. I don't know how to implement that without storing tags, unless there are exist continuations in future (to run code after the gate).

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-90508551.

Alberto.

NCrashed commented 9 years ago

Can this be used instead of wcallback?

Don't think so, the semantic is different. wcallback is more general as it allows to produce new type b and doesn't form infinite update loop inside.

the old version that run in tryplayg.herokuapp.com produces a lot of extra spans. please use the new one (use the docker image)

My project is quite big (~15 modules) thus I use hackage version (with direct building via cabal file) that has the problem with spans.

Why not myWidget :: State -> Widget State myWidget state = do -- some render timeout 1000 calculateNewState state

I don't want add extra "sleeps" (timeout 1000) without a really need. The wloop implementation rerenders only on event, and if I remove timeout 1000, application crashes with too much recursion in js console.

agocorona commented 9 years ago

Yes the wcallback leaks spans even in the last version. It is something that I have to fix or remove it

2015-04-08 1:03 GMT+02:00 Anton Gushcha notifications@github.com:

Can this be used instead of wcallback?

Don't think so, the semantic is different. wcallback is more general as it allows to produce new type b and doesn't form infinite update loop inside.

the old version that run in tryplayg.herokuapp.com produces a lot of extra spans. please use the new one (use the docker image)

My project is quite big (~15 modules) thus I use hackage version (with direct building via cabal file) that has the problem with spans.

Why not myWidget :: State -> Widget State myWidget state = do -- some render timeout 1000 calculateNewState state

I don't want add extra "sleeps" (timeout 1000) without a really need. The wloop implementation rerenders only on event, and if I remove timeout 1000, application crashes with too much recursion in js console.

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-90754160.

Alberto.

agocorona commented 9 years ago

In most of the cases, wcallbackcan be avoided and use at It is more readable and flexible.

2015-04-08 3:46 GMT+02:00 Alberto G. Corona agocorona@gmail.com:

Yes the wcallback leaks spans even in the last version. It is something that I have to fix or remove it

2015-04-08 1:03 GMT+02:00 Anton Gushcha notifications@github.com:

Can this be used instead of wcallback?

Don't think so, the semantic is different. wcallback is more general as it allows to produce new type b and doesn't form infinite update loop inside.

the old version that run in tryplayg.herokuapp.com produces a lot of extra spans. please use the new one (use the docker image)

My project is quite big (~15 modules) thus I use hackage version (with direct building via cabal file) that has the problem with spans.

Why not myWidget :: State -> Widget State myWidget state = do -- some render timeout 1000 calculateNewState state

I don't want add extra "sleeps" (timeout 1000) without a really need. The wloop implementation rerenders only on event, and if I remove timeout 1000, application crashes with too much recursion in js console.

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-90754160 .

Alberto.

Alberto.

NCrashed commented 9 years ago

Thank you for the help.

In most of the cases, wcallbackcan be avoided and use at It is more readable and flexible.

Yep, but it requires insertion point, explicit management of element-wrapper.

agocorona commented 9 years ago

Ok, I know how to avoid the wcallback span's: using outerHTML insertion instead of innerHTML

2015-04-08 12:09 GMT+02:00 Anton Gushcha notifications@github.com:

Thank you for the help.

In most of the cases, wcallbackcan be avoided and use at It is more readable and flexible.

Yep, but it requires insertion point, explicit management of element-wrapper.

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-90869538.

Alberto.

NCrashed commented 9 years ago

It would be great!

agocorona commented 9 years ago

what is your project about , by the way, If that can be made public?. If not you could send me a personal mail...

2015-04-08 12:22 GMT+02:00 Anton Gushcha notifications@github.com:

It would be great!

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-90872610.

Alberto.

NCrashed commented 9 years ago

Yep, it is public. https://github.com/NCrashed/bmstu-radio-problem-haste

I am preparing a practice task for BMSTU course. The app demonstrates genetic algorithm operation on radio problem task (choose optimal placement of radio towers in fixed size field). It is almost done. I am going to localize (at the moment, all labels in Russian) it and make fpcomplete article as soon as everything looks well.

agocorona commented 9 years ago

That really looks great.

Hope to see it soon in FPcomplete to get a detailed explanation

2015-04-08 14:54 GMT+02:00 Anton Gushcha notifications@github.com:

Yep, it is public. https://github.com/NCrashed/bmstu-radio-problem-haste

I am preparing a practice task for BMSTU course. The app demonstrates genetic algorithm operation on radio problem task (choose optimal placement of radio towers in fixed size field). It is almost done. I am going to localize (at the moment, all labels in Russian) it and make fpcomplete article as soon as everything looks well.

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-90905517.

Alberto.

agocorona commented 9 years ago

Hi Anton. How are you? Did you write something about the development? It would be nice to see it and post it in Reddit...

2015-04-08 15:09 GMT+02:00 Alberto G. Corona agocorona@gmail.com:

That really looks great.

Hope to see it soon in FPcomplete to get a detailed explanation

2015-04-08 14:54 GMT+02:00 Anton Gushcha notifications@github.com:

Yep, it is public. https://github.com/NCrashed/bmstu-radio-problem-haste

I am preparing a practice task for BMSTU course. The app demonstrates genetic algorithm operation on radio problem task (choose optimal placement of radio towers in fixed size field). It is almost done. I am going to localize (at the moment, all labels in Russian) it and make fpcomplete article as soon as everything looks well.

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-90905517 .

Alberto.

Alberto.

NCrashed commented 9 years ago

Hi. I am flying (a plane is tommorow) to a hike for two weeks, therefore I won't be able even to connect with outer world. I am going to prepare article after the vacation.

agocorona commented 9 years ago

Great! nice to hear that.

2015-04-30 23:55 GMT+02:00 Anton Gushcha notifications@github.com:

Hi. I am flying (a plane is tommorow) to a hike for two weeks, therefore I won't be able even to connect with outer world. I am going to prepare article after the vacation.

— Reply to this email directly or view it on GitHub https://github.com/agocorona/hplayground/issues/7#issuecomment-97982339.

Alberto.