Restrict records using Opaque Types
This topic has been covered by Elm Patterns​
If you're writing a package use a pipeline API instead.
Problem
Solution
Main.elm
1
type alias Movie =
2
{ title : String
3
, rating : Int
4
}
5
​
6
{-| adds a Rating to a Movie,
7
Only allows ratings between 1 and 5.
8
-}
9
addRating : Int -> Movie -> Movie
10
addRating rating movie =
11
{ movie | rating = rating}
Copied!
Movie.elm
1
module Movie exposing (Movie,fromTitle,addRating)
2
​
3
type Movie =
4
Movie
5
{ title : String
6
, rating : Int
7
}
8
​
9
{-| adds a Rating to a Movie,
10
Only allows ratings between 1 and 5.
11
-}
12
addRating : Int -> Movie -> Maybe Movie
13
addRating rating (Movie movie) =
14
if 1 <= rating && rating <= 5 then
15
Just <| Movie { movie | rating = rating}
16
else
17
Nothing
18
​
19
{-| Constructs a Movie from a Title
20
-}
21
fromTitle : String -> Movie
22
fromTitle title =
23
Movie
24
{ title = title
25
, rating = 0
26
}
Copied!
Main.elm
1
import Movie exposing (Movie)
2
​
3
newMovie : String -> Int -> Movie
4
newMovie title rating =
5
let
6
movie = Movie.fromTitle title
7
in
8
movie
9
|> Movie.addRating rating
10
|> Maybe.withDefault movie
Copied!

Question

How can I only allow specific states for my type?

Answer

Place the type into a new File and don't expose the constructor: exposing (Movie) instead of exposing(Movie(..)). Then write your own constructors.
We can unwrap function parameters like this:
1
addRating rating (Movie movie) =
2
...
Copied!

Further reading