miso
Copyright(C) 2016-2026 David M. Johnson
LicenseBSD3-style (see the file LICENSE)
MaintainerDavid M. Johnson <code@dmj.io>
Stabilityexperimental
Portabilitynon-portable
Safe HaskellSafe-Inferred
LanguageHaskell2010

Miso.Effect

Description

This module defines Effect, Sub and Sink types, which are used with the update function and subs field of the Component.

Synopsis

Effect

Types

type Effect parent model action = RWS (ComponentInfo parent) [Schedule action] model () Source #

A monad for succinctly expressing model transitions in the update function.

Effect is a RWS, where the State allows modification to model. It's also a Writer Monad, where the accumulator is a list of scheduled IO actions. Multiple actions can be scheduled using tell from the mtl library and a single asynchronous action can be scheduled using io_.

An Effect represents the results of an update action.

It consists of the updated model and a list of subscriptions. Each Sub is run in a new thread so there is no risk of accidentally blocking the application.

Tip: use the Effect monad in combination with the stateful Miso.Lens operators (all operators ending in "="). The following example assumes the lenses field1, counter and field2 are in scope and that the LambdaCase language extension is enabled:

myComponent = Component
  { update = \case
      MyAction1 -> do
        field1 .= value1
        counter += 1
      MyAction2 -> do
        field2 %= f
        io_ $ do
          consoleLog "Hello"
          consoleLog "World!"
  , ...
  }

type Sub action = Sink action -> IO () Source #

Type synonym for constructing subscriptions.

For example usage see Miso.Subscription

The Sink function is used to write to the global event queue.

type Sink action = action -> IO () Source #

Function to write to the global event queue for processing by the scheduler.

type DOMRef = JSVal Source #

Type to represent a DOM reference

data ComponentInfo parent Source #

This is the 'Reader r' in Effect. Accessible via ask. It holds a phantom type for parent. This is used as a witness when calling the parent function. It gives access to Component metadata such as the DOMRef the Component was mounted on and the ComponentId associated with it.

IO

data Schedule action Source #

Represents a scheduled Effect that is executed either synchronously or asynchronously.

All IO is by default asynchronous, use the sync function for synchronous execution. Beware sync can block the render thread for a specific Component.

N.B. During Component unmounting, all effects are evaluated synchronously.

Since: 1.9.0.0

Constructors

Schedule Synchronicity (Sink action -> IO ()) 

data Synchronicity Source #

Type to indicate if effects should be handled asynchronously or synchronously.

Constructors

Async 
Sync 

Instances

Instances details
Show Synchronicity Source # 
Instance details

Defined in Miso.Effect

Eq Synchronicity Source # 
Instance details

Defined in Miso.Effect

Combinators

(<#) :: model -> IO action -> Effect parent model action infixl 0 Source #

Smart constructor for an Effect with exactly one action.

(#>) :: IO action -> model -> Effect parent model action infixr 0 Source #

Effect smart constructor, flipped

batch Source #

Arguments

:: [IO action]

Batch of IO actions to execute

-> Effect parent model action 

Smart constructor for an Effect with multiple IO actions.

Since: 1.9.0.0

batch_ :: [IO ()] -> Effect parent model action Source #

Like batch but actions are discarded

Since: 1.9.0.0

io Source #

Arguments

:: IO action

IO action to execute asynchronously

-> Effect parent model action 

Schedule a single IO action for later execution.

Note that multiple IO action can be scheduled using tell from the mtl library.

Since: 1.9.0.0

io_ Source #

Arguments

:: IO ()

IO action to execute asynchronously

-> Effect parent model action 

Like io but doesn't cause an action to be dispatched to the update function.

This is handy for scheduling IO computations where you don't care about their results or when they complete.

Note: The result of IO a is discarded.

Since: 1.9.0.0

sync Source #

Arguments

:: IO action

IO action to execute synchronously

-> Effect parent model action 

Schedule a single IO action, executed synchronously. For asynchronous execution, see io.

Please use this with caution because it will block the render thread.

Since: 1.9.0.0

sync_ Source #

Arguments

:: IO ()

IO action to execute synchronously

-> Effect parent model action 

Like sync, except discards the result.

Since: 1.9.0.0

for Source #

Arguments

:: Foldable f 
=> IO (f action)

actions executed in batch.

-> Effect parent model action 

Like io but generalized to any instance of Foldable

This is handy for scheduling IO computations that return a Maybe value

Since: 1.9.0.0

issue Source #

Arguments

:: action

action to raise

-> Effect parent model action 

Issue a new action to be processed by update.

data Action = HelloWorld
type Model  = Int

'update' :: Action -> 'Effect' parent Model Action
'update' = \\case
  Click -> 'issue' HelloWorld

Since: 1.9.0.0

withSink Source #

Arguments

:: (Sink action -> IO ())

Callback function that provides access to the underlying Sink.

-> Effect parent model action 

withSink allows users to write to the global event queue. This is useful for introducing IO into the system. A synonym for tell, specialized to Effect.

A use-case is scheduling an IO computation which creates a 3rd-party JS widget which has an associated callback. The callback can then call the sink to turn events into actions.

'update' FetchJSON = 'withSink' $ \sink -> getJSON (sink . ReceivedJSON) (sink . HandleError)

Since: 1.9.0.0

mapSub :: (a -> b) -> Sub a -> Sub b Source #

Turn a Sub that consumes actions of type a into a Sub that consumes actions of type b using the supplied function of type a -> b.

noop :: action -> Effect parent model action Source #

Helper for Component construction, when you want to ignore the update function temporarily, or permanently.

Since: 1.9.0.0

beforeAll :: IO () -> Effect parent model action -> Effect parent model action Source #

Performs the given IO action before all IO actions collected by the given effect.

Example usage:

-- delays connecting a websocket by 100000 microseconds
beforeAll (liftIO $ threadDelay 100000) $ websocketConnectJSON OnConnect OnClose OnOpen OnError

afterAll :: IO () -> Effect parent model action -> Effect parent model action Source #

Performs the given IO action after all IO actions collected by the given effect.

Example usage:

-- log that running the a websocket Effect completed
afterAll (consoleLog "Done running websocket effect") $ websocketConnectJSON OnConnect OnClose OnOpen OnError

modifyAllIO :: (IO () -> IO ()) -> Effect parent model action -> Effect parent model action Source #

Modifies all IO collected by the given Effect.

All IO expressions collected by Effect can be evaluated either synchronously or asynchronously (the default).

This function can be used to adjoin additional actions to all IO expressions in an Effect. For examples see beforeAll and afterAll.

Lens

componentInfoDOMRef :: Lens (ComponentInfo parent) DOMRef Source #

Lens for accessing the underlying Component DOMRef.

  update = case
    SomeAction -> do
      domRef <- view componentDOMRef
      someAction domRef

Since: 1.9.0.0

componentInfoParentId :: Lens (ComponentInfo parent) ComponentId Source #

Lens for accessing the parents's ComponentId from ComponentInfo.

update = case
  SomeAction -> do
    compParentId <- view componentParentId
    someAction compParentId

Since: 1.9.0.0

componentInfoId :: Lens (ComponentInfo parent) ComponentId Source #

Lens for accessing the ComponentId from ComponentInfo.

  update = case
    SomeAction -> do
      compId <- view componentInfoId
      someAction compId

Since: 1.9.0.0

Internal

runEffect :: Effect parent model action -> ComponentInfo parent -> model -> (model, [Schedule action]) Source #

Internal function used to unwrap an Effect