pijul nest
guest [sign in]

Fork channel

Create a new channel as a copy of main.

Rename channel

Rename main to:

Delete channel

Delete main? This cannot be undone.

Debounce.hs
-- | Take incoming Aff requests, and perform them sequentially.
-- | In case a request is received while another is being performed,
-- | queue the new request instead. The queued request will be performed once the
-- | one before finishes. The request queue contains at most a single request;
-- | in case multiple ones are added, only the newest one stays.
-- |
-- | This ensures optimal semantics in the following sense: At every point in time,
-- | the freshest possible result is returned to the caller.

module Frontend.Component.Debounce where

import Prelude

import Data.Maybe (Maybe(..))
import Data.Newtype (class Newtype)
import Effect.Aff (Aff)
import Effect.Aff.Class (class MonadAff, liftAff)
import Halogen as H
import Halogen.HTML as HH


newtype Output t = Output t
derive instance newtypeOutput :: Newtype (Output t) _

data Query t a = Query (Aff t) a

type State t = { seeking :: Boolean, seekQueue :: Maybe (Aff t) }

debounce :: forall input t m. MonadAff m => H.Component HH.HTML (Query t) input (Output t) m
debounce =
  H.mkComponent
    { initialState: \_ -> { seeking: false, seekQueue: Nothing }
    , render: const $ HH.text ""
    , eval: H.mkEval $ H.defaultEval { handleQuery = handleQuery }
    }
  where

  handleQuery :: forall action a. Query t a -> H.HalogenM (State t) action () (Output t) m (Maybe a)
  handleQuery = case _ of
    Query computation a -> do
      H.modify_ _ { seekQueue = Just computation }
      seeking <- H.gets _.seeking
      case seeking of
        true -> pure (Just a)
        false -> do
          H.modify_ _ { seeking = true, seekQueue=Nothing }
          res <- liftAff computation
          H.modify_ _ { seeking = false }
          H.raise $ Output res
          q <- H.gets _.seekQueue
          case q of
            Nothing -> pure (Just a)
            Just v -> handleQuery (Query v a)