# Types - Primitive, Named, Phantom, Opaque, Custom, State Machines, and Type Driven Design

**URL:** <https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680>\
**Category:** Learn\
**Created:** [November 17, 2019, 7:35pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680 "2019-11-17T19:35:29Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [November 17, 2019, 7:35pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/1 "2019-11-17T19:35:29Z")

</div>

A question in Elm Slack lead to some interesting responses and great links to resources about Types in Elm.

Please jump in to add to the conversation or post up insights or links. Here, or there:  
[https://elmlang.slack.com/archives/C0CJ3SBBM/p1573891184226800](https://elmlang.slack.com/archives/C0CJ3SBBM/p1573891184226800)

**The OP** :  
Can anyone recommend an Elm book which promotes the following:

- strict avoidance of primitive obsession (an Anaemic Domain model that is non-semantic):
- strict avoidance of conditionals and booleans (except where unavoidable)
- strict adherence to type parsing instead of data validation  
[https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/)
- Phantom types (making it impossible to create malformed data, related to type parsing)
- Opaque types (hiding the implementation of type constructors)
- Making Phantom types Opaque so that only the Phantom type can be used for construction
- Algebraic Data Types for advanced modelling of domain data entities
- Finite State Machines and State Charts for advanced domain modelling (making full use of both types and functions).
- Functional Domain Driven Design

Finding a book in which the author uses all of the above together would be ideal.

---

<div class="post-metadata">

**Author:** ![zoul](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/zoul/32/2697_2.png) [@zoul](https://discourse.elm-lang.org/u/zoul)\
**Post date:** [November 18, 2019, 12:53pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/2 "2019-11-18T12:53:12Z")

</div>

_You need to sign in to see this page._ Could we repost some of that here? I hate when useful stuff ends up siloed somewhere.

---

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [November 18, 2019, 1:22pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/3 "2019-11-18T13:22:53Z")

</div>

Subsequent posts here:  
As I see it, all of these topics are a natural progression from primitive data types.When type driven design is explained within a DDD philosophy a lot of things fell into place for me and I wish I had known about them from the very beginning (trying to learn JS so many things didn’t make sense till I encountered Elm’s strict functional typing and framed it within the core of Functional DDD type driven design).

This single comment showed me that all of the above are a great fit for functional domain modelling and developing semantic domain abstractions in types:

> <https://softwareengineering.stackexchange.com/questions/317587/is-it-still-valid-to-speak-about-anemic-model-in-the-context-of-functional-progr/317599#317599>

---

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [November 18, 2019, 1:28pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/4 "2019-11-18T13:28:07Z")

</div>

Scott Wlaschin writes about all of the above (for fsharp). Here is an article about constrained types:  
[https://fsharpforfunandprofit.com/posts/designing-with-types-more-semantic-types/](https://slack-redir.net/link?url=https%3A%2F%2Ffsharpforfunandprofit.com%2Fposts%2Fdesigning-with-types-more-semantic-types%2F)

---

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [November 18, 2019, 1:28pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/5 "2019-11-18T13:28:26Z")

</div>

From **joelq** :  
While I don’t think any of the Elm books out there dig much into these concepts, there is definitely a decent amount of material on these topics in the Elm community. Here are some resources Blog posts:

• **Modeling Currency in Elm using Phantom Types** (this is a nice concrete example of phantom types)

> **[Modeling Currency in Elm using Phantom Types](https://thoughtbot.com/blog/modeling-currency-in-elm-using-phantom-types)**
>
> Lean on Elm’s friendly compiler to enforce currency-related constraints.

• **Shaping Values with Types** (taking “making impossible states impossible” to an extreme)

> **[Shaping Values with Types](https://thoughtbot.com/blog/shaping-values-with-types)**
>
> Elm types like String can represent an infinite number of possible values. Let’s use types to reduce that number and better declare intent.

• **Modeling with Union Types**

> **[Modeling with Union Types](https://thoughtbot.com/blog/modeling-with-union-types)**
>
> Clean up Maybe by modeling multiple shapes of data with union types.

• **Booleans and Enums** (alternatives to using boolean flags)

> **[Booleans and Enums](https://thoughtbot.com/blog/booleans-and-enums)**
>
> Refactor common Boolean smells using enums (union types).

• **Lessons Learned: Avoiding Primitives in Elm** (a look at the “wrapper type” pattern AKA “newtype”)

> **[Lessons Learned: Avoiding Primitives in Elm](https://thoughtbot.com/blog/lessons-learned-avoiding-primitives-in-elm)**
>
> Switching from primitive types to product types can improve confidence in correctness and compiler errors, but not without a cost.

• **Using Elm Types to Prevent Loggin SSNs** (a look at opaque types)

> **[Using elm types to prevent logging social security #’s](https://incrementalelm.com/articles/exit-gatekeepers/)**
>
> One of the most successful techniques I’ve seen for making sure you don’t break elm code the next time you touch it is a technique I call an Exit Gatekeeper .

• **Elm Slays a UI Antipattern** (a look at replacing boolean flags)  
[http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html](http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html)

• **Invariant-driven Development**

> **[Invariant Driven Development](https://medium.com/@ckoster22/invariant-driven-development-8231add95e33)**
>
> What’s true of every bug found in the field? … It passed the type checker \[and it\] passed all of the tests. - Rich Hickey

Conference Talks:  
**A Number By Any Other Name** (Joël Quenneville, Elm in the Spring 2019)

• **Make Data Structures** (Richard Feldman, ElmEurope 2018)

• **Solving the Boolean Identity Crisis** (Jeremy Fairbank, ElmConf 2017)

• **Making Impossible States Impossible** (Richard Feldman, ElmConf 2016)

---

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [November 18, 2019, 1:29pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/6 "2019-11-18T13:29:15Z")

</div>

From **charliek:**  
In addition to the IDD blog post Joel linked above I have a few other posts that cover several related topics including phantom types, never type, extensible records, opaque types, with\* functions, fuzz testing, pure randomness, and a few others. I hope you find something helpful in that list!

> **[Charlie Koster – Medium](https://medium.com/@ckoster22)**
>
> Read writing from Charlie Koster on Medium. Advocate of technology and techniques that move the tech industry forward. charliek on Elm slack. Every day, Charlie Koster and thousands of other voices read, write, and share important stories on Medium.

From **joelq** :  
100% to [@charliek](https://elmlang.slack.com/team/U0VQVR50S)’s Advanced Types in Elm series:

1. **Opaque Types**  
[https://medium.com/@ckoster22/advanced-types-in-elm-opaque-types-ec5ec3b84ed2](https://medium.com/@ckoster22/advanced-types-in-elm-opaque-types-ec5ec3b84ed2)

2. **Extensible Records**  
[https://medium.com/@ckoster22/advanced-types-in-elm-extensible-records-67e9d804030d](https://medium.com/@ckoster22/advanced-types-in-elm-extensible-records-67e9d804030d)

3. **The `Never` Type**  
[https://medium.com/@ckoster22/advanced-types-in-elm-the-never-type-ca9b3297bbd4](https://medium.com/@ckoster22/advanced-types-in-elm-the-never-type-ca9b3297bbd4)

4. **Phantom Types**  
[https://medium.com/@ckoster22/advanced-types-in-elm-phantom-types-808044c5946d](https://medium.com/@ckoster22/advanced-types-in-elm-phantom-types-808044c5946d)

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [November 18, 2019, 2:02pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/7 "2019-11-18T14:02:31Z")

</div>

Good collection of resources, and thanks for taking initiative to try and gather some of this stuff together. I don’t think you’ll find a book or any resource that covers it all - but certainly a great set of resources for someone who might want to write such a book.

You mentioned state machines? Here are some of the discussions that have been on here around that topic:

> [@Can phantom types be used to restrict the possible transitions in a state machine?](https://discourse.elm-lang.org/t/can-phantom-types-be-used-to-restrict-the-possible-transitions-in-a-state-machine/508):
>
> Hi, there was some discussion about state machines in Elm on Slack and it was suggested that it might be possible to use phantom types to control possible state transitions in a state machine. I have no idea how. Suppose you have some set of states defined as a tagged union: type Game = Loading | Ready | InPlay GameState -- GameState models score, position, enemies still alive etc. | GameOver Int -- Final score These states form a loop, once you reach GameOver you can go back to Rea…

> [@Elm-Action - Update your Model using a State Machine](https://discourse.elm-lang.org/t/elm-action-update-your-model-using-a-state-machine/3761):
>
> As your Elm project gets bigger, you start having multiple pages, all with their model/update/view. Setting up your main update function to pass the Msg to the correct page and then convert the response back to a (Model,Cmd Msg) is quite tricky and from personal experience I can tell you: if you do it wrong, its very hard to read and even to refactor. Today I present to you to an out-of-the-box solution that even prevents you from writing wrong or dead code. [https://package.elm-lang.org/package…](https://package.elm-lang.org/packages/Orasund/elm-action/latest/)

---

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [November 18, 2019, 3:05pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/8 "2019-11-18T15:05:56Z")

</div>

Thanks for the links to discussions about State Machines.

David Khourshid responded to a question I had about how far we could go modelling state machines with types and he said:  
Something important to keep in mind: state machines and statecharts _can_ model implementation details, but _should_ model higher-level abstract requirements and use-case scenarios. That’s their main purpose (in terms of app development).

Type systems _cannot_ model higher-level abstract requirements as they are not a modeling language. You can fake it a little, but you can’t look at a set of types and immediately translate those to e.g., business requirements.

In other words, these are two separate things that can work together. Type systems can model the implementation details, and state machines/statecharts can model the app at a higher level of abstraction.

> **[State machines and charts using Elm's type system and Algebraic Data Types ·...](https://spectrum.chat/statecharts/general/state-machines-and-charts-using-elms-type-system-and-algebraic-data-types~489cc9a8-b3cd-4e1a-813c-5b373864f258)**
>
> David Khourshid introduced the JS world to finite state machines and charts and I was lucky enough to learn a little from his work. I was very keen on…

I’ve not seen much interest amongst the Elm community for a more formalised implementation of FSMs and Charts and I began to think that perhaps this might be due to Elm’s excellent type system and the level of FSMs that can be created with it.

In Xstate there are machine and chart functions that consume machine templates represented in JSON. Robot.js makes machines and charts composable.

```auto
const promiseMachine = Machine({
  id: 'promise',
  initial: 'pending',
  states: {
    pending: {
      on: {
        RESOLVE: 'resolved',
        REJECT: 'rejected'
      }
    },
    resolved: {
      type: 'final'
    },
    rejected: {
      type: 'final'
    }
  }
});

```

I can’t help but see FSMs as a key part of (and extension to) designing with types and FDDD.

It is interesting that many are recommending these abstractions, including FSMs and Charts, be used as apps get bigger. But that feels counter intuitive to me. Sure, a very formalised FSM implementation might be too much for smaller apps but why wouldn’t we think and design with them from the start?

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [November 18, 2019, 3:44pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/9 "2019-11-18T15:44:09Z")

</div>

> [@nickwalt](#):
>
> I’ve not seen much interest amongst the Elm community for a more formalised implementation of FSMs

The approach I took was a bit more formal - I used phantom types to define the state transitions, so that the compiler could type check the state machine and enforce its correct operation. I still like this approach, since I tend to sketch state machines on paper prior to implementation, but I do think it is probably a bit heavy handed.

I liked the directness of the approach taken in `elm-action`, because you are essentially defining the state machine at the same time as writing the `update` function; it is more immediate and better suited to interactively developing - basically doing the pen and paper sketches in code.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [November 18, 2019, 3:47pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/10 "2019-11-18T15:47:11Z")

</div>

Some links to discussion about refinement types and enums in Elm. These are all opaque types but specific applications opaque types.

> [@How to do enums in Elm](https://discourse.elm-lang.org/t/how-to-do-enums-in-elm/1353):
>
> TL;DR: I’ve made a working Ellie for this if you want to play around: [https://ellie-app.com/nt22pfXCtKa1](https://ellie-app.com/nt22pfXCtKa1) I’ve seen a few comments around how working with enums suck in Elm. I believe much of the frustration comes from trying to re-implement in Elm a language feature that exists in other languages. As a result of applying the wrong kind of thinking, the wrong abstraction is reached and Elm gets the blame. So while I’m no expert, the following approach may lessen the pain that some people feel. L…

> [@Elm-Refine: Proposal](https://discourse.elm-lang.org/t/elm-refine-proposal/3857):
>
> Greetings everyone, I’m currently studying computer mathematics at the University of Linz/Austria and am now working on my master-thesis: Refinement types for Elm. In this post I will first explain the main concept and then propose a syntax. I would be grateful if you could give me feedback regarding the syntax. What are Refinement Types? Let’s look at the following example. {-| @refine \int -\> int /= 0 -} type alias IntWithoutZero = Int dividedBy : IntWithoutZero -\> Int -\> Int dividedBy…

> [@Best practice for guarded types?](https://discourse.elm-lang.org/t/best-practice-for-guarded-types/4590):
>
> I’m not actually sure what the best terminology is here, a guarded type, a restricted type? The idea is to wrap a basic type in an opaque custom type, and expose a lower case constructor for it, such that only instances meeting certain guard conditions can ever be created. An example: module Unitary exposing (Unitary, unitary, value) -- Unitary is opaque. {-| Numbers between zero and one. -} type Unitary = Unitary Float unitary : Float -\> Maybe Unitary unitary val = if val \< 0 then …

---

<div class="post-metadata">

**Author:** ![joelq](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/joelq/32/445_2.png) [@joelq](https://discourse.elm-lang.org/u/joelq)\
**Post date:** [November 18, 2019, 9:22pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/11 "2019-11-18T21:22:46Z")

</div>

If you’re interested in modeling state machines, you may find this article series useful:

> **[Finite-State Machines, Part 1: Modeling with Haskell Data Types | Oskar...](https://wickstrom.tech/finite-state-machines/2017/11/10/finite-state-machines-part-1-modeling-with-haskell.html)**
>
> Software design, testing, functional programming, and other delightful things.

It’s written in Haskell. Part 1 starts with something that looks a lot like the Elm Architecture.

---

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [November 19, 2019, 12:09am UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/12 "2019-11-19T00:09:21Z")

</div>

@joelq  
@rupert

Thanks for the links.

Scott Wlaschin moves his type designs into state machines in his [series of articles about designing with types](https://fsharpforfunandprofit.com/posts/designing-with-types-representing-states/).

Although, he keeps the machines based on types and I was curious about a next level of possible FSM abstraction that builds on his typed implementation.

Scott’s implementation from a FDDD perspective is of special interest, too. Which is in stark contrast to a few of the implementations in the links which do not appear to have any FDDD thinking and which exhibit very anaemic models.

But it’s not my intention to focus on state machines and digress from the main point of this thread, which is all about beautiful Elm types 🙏

---

<div class="post-metadata">

**Author:** ![progger](https://avatars.discourse-cdn.com/v4/letter/p/5daacb/32.png) [@progger](https://discourse.elm-lang.org/u/progger)\
**Post date:** [November 19, 2019, 6:19am UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/13 "2019-11-19T06:19:33Z")

</div>

I’ve just been playing around with state machine ideas in a new elm app, and so far I like it. I have pages, each of which is a module with its own view, update and etc. But here each page’s update function returns a state transition rather than (model, cmd).

For instance, Viewer.update can transition to itself by returning Viewer.View Viewer.Model. Or, it can transition to List by returning Viewer.List List.Model. The app inits into Loader, which awaits a payload of data, then transitions to List by returning Loader.List . You can check it out here:

> <https://github.com/bburdette/pdfq/blob/master/elm/src/Main.elm>

I’m not completely sure if its a good idea or not - so far the app is fairly simple. But I’ve had good results from state machines before, in other languages. I like the clarity of the returned transitions.

_import_ cycles are an issue, but you can deal with that by having Main interpret the transition args, or by using a type variable to store unknown state, as Viewer does.

---

<div class="post-metadata">

**Author:** ![Jess\_Bromley](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jess_bromley/32/3396_2.png) [@Jess\_Bromley](https://discourse.elm-lang.org/u/Jess_Bromley)\
**Post date:** [November 20, 2019, 1:05am UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/14 "2019-11-20T01:05:04Z")

</div>

> [@joelq](#):
>
> If you’re interested in modeling state machines, you may find this article series useful:
> 
> ![](https://wickstrom.tech/assets/icon.png) [wickstrom.tech](https://wickstrom.tech/finite-state-machines/2017/11/10/finite-state-machines-part-1-modeling-with-haskell.html)
> 
> ### [Finite-State Machines, Part 1: Modeling with Haskell Data Types | Oskar…](https://wickstrom.tech/finite-state-machines/2017/11/10/finite-state-machines-part-1-modeling-with-haskell.html)
> 
> Software design, testing, functional programming, and other delightful things.
> 
> It’s written in Haskell. Part 1 starts with something that looks a lot like the Elm Architecture.

I was really interested by Part 2 of this article, particularly it’s talk about separating “Protocol” from “Implementation” in a FSM, and wanted to see if you could do something similar with Elm. It turns out you can. Here’s what I came up with (below).

It’s a totally toy model (and I don’t know how complicated an example you’d actually need before the overhead of this approach became worthwhile!), but it demonstrates that you can use phantom types to constrain what transitions are possible by writing a protocol (here in State.elm) while leaving the details of how those transitions take place to the implementation (Main.elm). The compiler then makes it impossible to violate this protocol.

This toy model simply asks you to pick a shade and then a colour of that shade. For simplicity the correct choice of colour here just relies on a correctly written view function, but with a bit more code I could have forced impossible states to be impossible easily enough… my focus was instead though to make impossible transitions impossible (which is what separating out “Protocol” from “Implementation” gives you).

**State.elm**

```elm
module State exposing (Done, Init, State, Working, data, finish, init, start)

type State x stateData
    = State x stateData

data : State x stateData -> stateData
data (State state sData) =
    sData

-- POSSIBLE STATES

type Init
    = Init

type Working
    = Working

type Done
    = Done

-- VALID TRANSITIONS

init : iData -> State Init iData
init internals =
    State Init internals

start : State Init iData -> (iData -> wData) -> State Working wData
start (State Init internals) updateFunc =
    State Working (updateFunc internals)

finish : State Working wData -> (wData -> eData) -> State Done eData
finish (State Working internals) updateFunc =
    State Done (updateFunc internals)

```

**Main.elm**

```elm
module Main exposing (main)

import Browser
import Html
import Html.Events as HEvents
import State exposing (State)

main : Program () Model Msg
main =
    Browser.sandbox
        { init = Initializing (State.init ())
        , update = update
        , view = view
        }

-- MODEL

type Model
    = Initializing (State State.Init ())
    | Running (State State.Working { shades : Shade })
    | Complete (State State.Done { colour : Colour })

type Shade
    = Reds
    | Greens
    | Blues

type Colour
    = Crimson
    | Scarlet
    | Emerald
    | Jade
    | Cerulean
    | Azure

-- UPDATE

type Msg
    = ChooseShade Shade
    | ChooseColour Colour

update : Msg -> Model -> Model
update msg model =
    case msg of
        ChooseShade shade ->
            case model of
                Initializing data ->
                    State.start data (always { shades = shade }) |> Running

                _ ->
                    model

        ChooseColour col ->
            case model of
                Running data ->
                    State.finish data (always { colour = col }) |> Complete

                _ ->
                    model

-- VIEW

view : Model -> Html.Html Msg
view model =
    case model of
        Initializing _ ->
            Html.div []
                [Html.p [] [Html.text "What shade colour do you want?"]
                , Html.button [HEvents.onClick (ChooseShade Reds)] [Html.text "Red"]
                , Html.button [HEvents.onClick (ChooseShade Greens)] [Html.text "Greens"]
                , Html.button [HEvents.onClick (ChooseShade Blues)] [Html.text "Blues"]
                ]

        Running state ->
            let
                makeChoices typeNamePairs =
                    Html.div []
                        (Html.p [] [Html.text "What colour do you want?"]
                            :: List.map
                                (\( t, n ) ->
                                    Html.button
                                        [HEvents.onClick (ChooseColour t)]
                                        [Html.text n]
                                )
                                typeNamePairs
                        )
            in
            case (State.data >> .shades) state of
                Reds ->
                    makeChoices [( Crimson, "Crimson" ), ( Scarlet, "Scarlet" )]

                Greens ->
                    makeChoices [( Emerald, "Emerald" ), ( Jade, "Jade" )]

                Blues ->
                    makeChoices [( Cerulean, "Cerulean" ), ( Azure, "Azure" )]

        Complete state ->
            case (State.data >> .colour) state of
                Crimson ->
                    Html.text "You chose Crimson"

                Scarlet ->
                    Html.text "You chose Scarlet"

                Emerald ->
                    Html.text "You chose Emerald"

                Jade ->
                    Html.text "You chose Jade"

                Cerulean ->
                    Html.text "You chose Cerulean"

                Azure ->
                    Html.text "You chose Azure"

-- FORBIDDEN OPERATIONS
{- The following will not compile. We are not allowed to define new transitions outside
   of the state machine definition in State.elm

   forbidden : State State.Init iData -> (iData -> eData) -> State State.Done eData
   forbidden (State State.Init internals) updateFunc =
       State State.Done (updateFunc internals)
-}

```

Possibly this is already the approach taken in one of the Elm packages referenced above by @rupert and/or @Lucas_Payr, but I confess that I could never totally follow how they worked before! Now that I’ve worked through an example by hand I may go back again to try and understand exactly what they are doing…

---

<div class="post-metadata">

**Author:** ![Lucas\_Payr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lucas_payr/32/4993_2.png) [@Lucas\_Payr](https://discourse.elm-lang.org/u/Lucas_Payr)\
**Post date:** [November 20, 2019, 9:30am UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/16 "2019-11-20T09:30:57Z")

</div>

[the-sett/elm-state-machines](https://package.elm-lang.org/packages/the-sett/elm-state-machines/latest/) has not yet been mentioned. @the-sett had the same approach as you had: Using phantom types to model the transitions.

My package on the other hand uses no phantom types. I define the main type of my package as

```auto
type Action model msg transitionData exitAllowed =
    Action model msg transitionData exitAllowed

```

The Idea is that every page/state has its own Action type. In the update function you then provide the transition functions between the different Actions. If you make a mistake during the writing process, then the compiler will tell you.

Btw. the transition function will only look at the `transitionData`. And I also allow for a default transition (exiting). I use the `Never` type to keep my Action type as sharp as possible: If I don’t allow a transition, then the `transitionData` is `Never`, similarly if I don’t want to have a default exit transition, I can set `exitAllowed` to `Never`.

This is not the way state machines are typically modelled. But it makes a lot of sense in the context of web development.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [November 20, 2019, 10:03am UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/17 "2019-11-20T10:03:49Z")

</div>

> [@Lucas\_Payr](#):
>
> [the-sett/elm-state-machines](https://package.elm-lang.org/packages/the-sett/elm-state-machines/latest/) has not yet been mentioned. @the-sett had the same approach as you had: Using phantom types to model the transitions.

That package came out of the discussion linked to above around using phantom types to model the allowed state machine transitions.

It is fairly similar to @Jess_Bromley’s toy model above in that the state machine is defined separately to using it. You can find my implementation of a ‘toy model’ here: [Exploring State Machines with phantom types in Elm · GitHub](https://gist.github.com/rupertlssmith/88946c8d207d7ad64daf4360fef1ac42)

---

<div class="post-metadata">

**Author:** ![pzingg](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pzingg/32/1517_2.png) [@pzingg](https://discourse.elm-lang.org/u/pzingg)\
**Post date:** [November 26, 2019, 5:44pm UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/18 "2019-11-26T17:44:18Z")

</div>

This is the best thread yet for experienced Elm users. How about archiving these resources in an “Awesome Elm Patterns” on GitHub (which could go farther than just a discussion of type techniques)? I will do it but I have no cred.

---

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [November 27, 2019, 3:58am UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/19 "2019-11-27T03:58:38Z")

</div>

The Spectrum Statecharts forum hosts discussions all about State Machines and Charts and some interesting ideas might come out of posting some of the solutions from this thread into there.

> **[Spectrum](https://spectrum.chat/statecharts?tab=posts)**
>
> Where communities live.

If you post there it would be good to have a reference to it in a link here.

---

<div class="post-metadata">

**Author:** ![nickwalt](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/nickwalt/32/1283_2.png) [@nickwalt](https://discourse.elm-lang.org/u/nickwalt)\
**Post date:** [December 3, 2019, 6:21am UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/20 "2019-12-03T06:21:18Z")

</div>

This course is heavy on type-driven design and has episodes specifically teaching Opaque, Phantom, and Custom Types and using them together:

> **[Take Your Elm 0.19 Applications to the Next Level!](https://frontendmasters.com/courses/advanced-elm/)**
>
> Learn how to organize and scale your Elm applications with authentication, css-in-Elm, 3rd party JS libraries, and more!

I’ll be going through it over the Christmas break. Really looking forward to it. Though I suspect I’ll be struggling to understand much of the implementation detail.

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [December 13, 2019, 6:21am UTC](https://discourse.elm-lang.org/t/types-primitive-named-phantom-opaque-custom-state-machines-and-type-driven-design/4680/21 "2019-12-13T06:21:20Z")

</div>

Closed on December 13, 2019, 6:21am UTC

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
