webbhuset / elm-actor-model / Webbhuset.Actor

Actor

When a component is incorporated in a system it becomes an Actor. The actor module implements the connections to the other components in the system. In practice that means mapping and sending the component's out messages to other actors in the system.

Here is an example of wrapping a login form component to an actor in a system.

This is the global model for the System:

module AppModel exposing (..)

type AppModel
    = LoginFormModel LoginForm.Model
    | OtherComponent ...

This is the global appMsg type for the System:

module AppMsg exposing (..)

type AppMsg
    = FormMsg LoginForm.MsgIn
    | AuthServiceMsg AuthService.MsgIn
    | OtherComponent ...

This is the login form actor:

module Actor.LoginForm exposing (..)

import Webbhuset.ActorSystem as System
import Webbhuset.Actor as Actor exposing (Actor)
import Component.LoginForm as LoginForm
import Component.AuthService as AuthService
import AppMsg exposing (AppMsg)
import AppModel exposing (AppModel)


actor : Actor LoginForm.Model AppModel AppMsg
actor =
    Actor.fromUI
        { wrapModel = AppModel.LoginFormModel
        , wrapMsg = AppMsg.FormMsg
        , mapIn = mapFormIn
        , mapOut = mapFormOut
        }
        LoginForm.component


mapFormIn : AppMsg -> Maybe LoginForm.MsgIn
mapFormIn appMsg =
    case appMsg of
        AppMsg.FormMsg formMsg ->
            Just formMsg

        _ ->
            Nothing


mapFormOut : PID -> LoginForm.MsgOut -> System.SysMsg name AppMsg
mapFormOut self formMsg =
    case formMsg of
        LoginForm.Submit user password ->
            AuthService.Login user password self
                |> AppMsg.AuthServiceMsg
                |> System.toAppMsg
                |> System.sendToSingleton AuthService


type alias PID =
Webbhuset.PID.PID

A PID is an identifier for a Process.

Create Actors from Components

fromUI : { wrapModel : compModel -> appModel, wrapMsg : msgIn -> appMsg, mapIn : appMsg -> Maybe msgIn, mapOut : PID -> msgOut -> SysMsg name appMsg } -> Webbhuset.Component.UI compModel msgIn msgOut -> Actor compModel appModel (SysMsg name appMsg)

Create an actor from a UI Component

fromService : { wrapModel : compModel -> appModel, wrapMsg : msgIn -> appMsg, mapIn : appMsg -> Maybe msgIn, mapOut : PID -> msgOut -> SysMsg name appMsg } -> Webbhuset.Component.Service compModel msgIn msgOut -> Actor compModel appModel (SysMsg name appMsg)

Create an actor from a Service Component

fromLayout : { wrapModel : compModel -> appModel, wrapMsg : msgIn -> appMsg, mapIn : appMsg -> Maybe msgIn, mapOut : PID -> msgOut -> SysMsg name appMsg } -> Webbhuset.Component.Layout compModel msgIn msgOut (SysMsg name appMsg) -> Actor compModel appModel (SysMsg name appMsg)

Create an actor from a Layout Component

For package authors.

You probably don't need this when you are using the actor model. These are useful if you need to create support for a different output type.


type alias Actor compModel appModel msg =
Webbhuset.ActorSystem.Actor compModel appModel (Html msg) msg

An actor is acomponent where the types are wrapped to fit the System types.


type alias Args name compModel appModel msgIn msgOut appMsg =
{ wrapModel : compModel -> appModel
, wrapMsg : msgIn -> appMsg
, mapIn : appMsg -> Maybe msgIn
, mapOut : PID -> msgOut -> SysMsg name appMsg 
}

Args

wrapSystem : (msgIn -> appMsg) -> (Webbhuset.Component.SystemEvent.SystemEvent -> Webbhuset.Component.SystemEvent.Handling msgIn) -> Webbhuset.Component.SystemEvent.SystemEvent -> PID -> Webbhuset.Component.SystemEvent.Handling (SysMsg name appMsg)

Convert a component onSystem field to an actor onSystem field

wrapSub : (msgIn -> appMsg) -> (compModel -> Platform.Sub.Sub msgIn) -> compModel -> PID -> Platform.Sub.Sub (SysMsg name appMsg)

Convert a component subs field to an actor subs field

wrapInit : Args name compModel appModel msgIn msgOut appMsg -> (PID -> ( compModel, List msgOut, Platform.Cmd.Cmd msgIn )) -> PID -> ( appModel, SysMsg name appMsg )

Convert a component init field to an actor init field

wrapUpdate : Args name compModel appModel msgIn msgOut msg -> (msgIn -> compModel -> ( compModel, List msgOut, Platform.Cmd.Cmd msgIn )) -> compModel -> SysMsg name msg -> PID -> ( appModel, SysMsg name msg )

Convert a component update field to an actor update field

sendTo : (msgIn -> appMsg) -> PID -> msgIn -> SysMsg name appMsg

Send to pid.