Anyone is able to create one of those.
Example Typed Tagged MetersTag ... Float
→ The right choice, as every Float is a valid description of Meters
Create a new tagged value.
Checked with isCheckedInternal/Public when annotated that wayModifying won't change the type.
Alter the value inside.
If the Typed was a Checked, it becomes a Tagged.
type alias Meters =
Typed Tagged MetersTag Public Int
go1km : Meters -> Meters
go1km =
Typed.map ((+) 1000)Use the values of 2 Typeds to return a Tagged result.
type alias PrimeNumber =
Typed Checked PrimeNumberTag Public Int
prime3 : PrimeNumber
prime3 =
tag 3 |> isChecked PrimeNumber
prime5 =
tag 5 |> isChecked PrimeNumberIn another module
type alias NonPrime =
Typed Checked NonPrimeTag Public Int
fromMultiplyingPrimes : Prime -> Prime -> NonPrime
fromMultiplyingPrimes aPrime bPrime =
Typed.map2 (*) aPrime bPrime
|> isChecked NonPrimeOnly someone with access to the tag constructor is able to create one of those.
In effect, this means that you can only let "validated" data be of this type.
Examaple ... Checked ... NaturalNumberTag Int
→ ✓ not every Int can be called a NaturalNumber, it must be checked!
After calling tag or modifying a checked value, you get a Tagged. To tell the type that the result value is Checked, use isChecked tag.
The type of tag might even change in that operation.
oddPlusOdd : Odd -> Odd -> Even
oddPlusOdd oddToAdd =
Typed.map2 (+) oddToAdd
>> isChecked EvenAnyone is able to access the value.
Use the values of 2 Public Typeds to return a result.
type alias Prime =
Typed Checked PrimeTag Public Int
prime3 =
tag 3 |> isChecked Prime
prime5 =
tag 5 |> isChecked PrimeAnywhere
val2 (+) prime3 prime5
--> 8
val2 Tuple.pair prime3 prime5
--> ( 3, 5 )
if val2 (<) onePrime otherPrime thenOnly the ones with access to the tag constructor can access the internalVal.
Meaning that access can be limited to
module Special exposing (Special)
type alias Special =
Typed Tagged SpecialTag Internal SpecialValueChecked)src
└ Special
└ Internal.elm
module Special.Internal exposing (SpecialTag(..))
└ SpecialPartA.elm
module SpecialPartA exposing (SpecialPartA)
import Special.Internal exposing (SpecialTag(..))
└ SpecialPartB.elm
module SpecialPartB exposing (SpecialPartB)
import Special.Internal exposing (SpecialTag(..))
elm.json 'exposed-modules' :
[ "SpecialPartA", "SpecialPartB" ]This generally helps hiding implementation details.
type alias OptimizedList a =
Typed Checked OptimizedListTag Internal (Implementation a)
type alias Implementation a =
{ list : List a, length : Int }
toList --...If you have an Internal, its value isn't readable by users.
If you have the tag however, you can access this data hidden from users.
Use the values of 2 Internal Typeds to return a result.
type alias OptimizedList a =
Typed
Checked
OptimizedListTag
Internal
{ list : List a, length : Int }
type OptimizedListTag
= OptimizedList
equal a b =
internalVal2 (==) OptimizedList a OptimizedList bA Codec to serialize Tagged Public Typeds.
A Codec to serialize Checkeds.
We don't trust that the values we encode still have the same promises as our Checkeds.
Choose a value it can convert from & to and serialize that.
module Nat exposing (serialize)
type NatTag
= Nat
serialize =
Serialize.int
|> Typed.serializeChecked Nat
(\int ->
if int >= 0 then
Ok int
else
Err "Int was negative, so it couldn't be decoded as a Nat"
)
module EfficientList exposing (serialize)
type EfficientListTag
= EfficientList
type alias EfficientList =
Typed Checked EfficientListTag
Internal { list : List a, length : Int }
serialize =
Serialize.map .list identity
|> Serialize.list
|> Typed.serializeChecked EfficientList
(\list ->
{ list = list
, length = List.length length
}
|> Ok
)
A value is wrapped in the
type Typedwith a phantomtag.A
Typed ... Meters ... Floatcan't be called aTyped ... Kilos ... Floatanymore!For
types with just 1 constructor with a value aTypedcan be a good replacement.who can construct such a value
CheckedTaggedwho can access the value
PublicInternalall promise additional type-safety.
reading types
Is saying:
mapworks on everyTypedand returns a value that is justTagged, but notChecked. ExplainingwhoCanAccess:PublicInternal,the result will be too.