Morph your types over a generic, case-able elm value
() MorphValue
Basically every module here has a MorphValue,
for example
of course you can combine them to reach other structures, like
Natural.Morph.integer
|> Morph.over Integer.Morph.valuefor a Natural
possibly incomplete step from and to a Record
building:
group|> part|> groupFinishWhat can go wrong while narrowing to a Record
Start assembling multiple parts.
Continue with |> part and after you're done, |> groupFinish.
An example translated from elm/json
import Decimal exposing (Decimal)
import Decimal.Morph
import RecordWithoutConstructorFunction exposing (RecordWithoutConstructorFunction)
import String.Morph
import Value
type alias Cause =
-- from lue-bird/elm-no-record-type-alias-constructor-function
RecordWithoutConstructorFunction
{ name : String
, percent : Decimal
, per100k : Decimal
}
value : MorphValue Cause
value =
Value.Morph.group
(\name percent per100k ->
{ name = name, percent = percent, per100k = per100k }
)
|> Value.Morph.part ( .name, "name" ) String.Morph.value
|> Value.Morph.part ( .percent, "percent" ) Decimal.Morph.value
|> Value.Morph.part ( .per100k, "per100k" ) Decimal.Morph.value
|> Value.Morph.groupFinishAnother example for tuples
{-| `( ..., ... )` `MorphValue`
Just use a record with descriptive names instead!
-}
tuple2 :
( Morph part0
, Morph part1
)
-> Morph ( part0, part1 )
tuple2 ( part0Morph, part1Morph ) =
Morph.named "2-tuple"
(Value.Morph.group
(\part0 part1 -> ( part0, part1 ))
|> Value.Morph.part ( Tuple.first, "part0" ) part0Morph
|> Value.Morph.part ( Tuple.second, "part1" ) part1Morph
|> Value.Morph.groupFinish
)
{-| `( ..., ..., ... )` `MorphValue`
Just use a record with descriptive names instead!
-}
tuple3 :
( Morph part0
, Morph part1
, Morph part2
)
-> Morph ( part0, part1, part2 )
tuple3 ( part0Morph, part1Morph, part2Morph ) =
Morph.named "3-tuple"
(Value.Morph.group
(\part0 part1 part2 -> ( part0, part1, part2 ))
|> Value.Morph.part ( \( part0, _, _ ) -> part0, "part0" ) part0Morph
|> Value.Morph.part ( \( _, part1, _ ) -> part1, "part1" ) part1Morph
|> Value.Morph.part ( \( _, _, part2 ) -> part2, "part2" ) part2Morph
|> Value.Morph.groupFinish
)Continue a group assembly MorphValue.
For example to morph a name String field, add
|> Value.Morph.part ( .name, "name" ) String.Morph.valueOnce you've assembled all parts, end the builder with groupFinish.
Conclude the Value.Morph.group |> Value.Morph.part builder
variant union MorphValue
Morph.choice|> Value.Morph.variantValue.Morph.choiceFinishDescribe another variant MorphValue
When you're done, end the builder with |> Value.Morph.choiceFinish
type User
= Guest GuestData
| SignedIn SignedInData
value : MorphValue User
value =
Morph.choice
(\variantGuest variantSignedIn user ->
case user of
Guest guest ->
variantGuest guest
SignedIn signedIn ->
variantSignedIn signedIn
)
|> Value.Morph.variant ( Guest, "guest" ) guestValue
|> Value.Morph.variant ( SignedIn, "signed in" ) signedInValue
|> Value.Morph.choiceFinishwhere guestValue : MorphValue GuestData and signedInValue : MorphValue SignedInData.
If a variant has no attached thing, use Value.Morph.unit
signValue : MorphValue Sign
signValue =
Morph.choice
(\positive negative sign ->
case sign of
Positive ->
positive ()
Negative ->
negative ()
)
|> Value.Morph.variant ( \() -> Positive, "Positive" ) Value.Morph.unit
|> Value.Morph.variant ( \() -> Negative, "Negative" ) Value.Morph.unit
|> Value.Morph.choiceFinishConclude a Morph.choice |> Value.Morph.variant builder.
with readable names. Use in combination with eachTag
part MorphValuevariant MorphValueValue.Morph.part order → no changeValue.Morph.parts → breaking changeSee also compact
With compact indexes. Use in combination with eachTag
part MorphValue index index in the buildervariant MorphValue index in the builderValue.Morph.part order → breaking changeValue.Morph.parts → no changeSee also descriptive
Morph.OneToOne from a Value,
reducing the amount of tag information in both directions
For Value, it's
...
|> Morph.over (eachTag compact)
-- or
...
|> Morph.over (eachTag descriptive)but the same thing works for Json, ... as well
build on existing ones
{-| `Posix` `MorphValue`
-}
posixValue : MorphValue Posix
posixValue =
Morph.named "posix"
(Morph.oneToOne
Time.posixToMillis
Time.millisToPosix
|> Morph.over Int.Morph.integer
|> Morph.over Integer.Morph.value
)or define new atoms, composed structures, ... (↓ are used by Json for example)
Morph to a AtomOrComposed's atom if possible
Morph to a AtomOrComposed's composed if possible
Since it takes a Value String, you use it
with compact or descriptive
to chain it with a MorphValue:
yourTypeMorphValue
|> Morph.over (Value.Morph.eachTag Value.Morph.compact)
|> Morph.overRow Value.Morph.bits
Morphbetween a given narrow value and a generic valueThe way it's set up, it allows tags that are either
descriptivecompact