for more information visit the package's GitHub page
Package contains the following modules:
a parser-printer: dev-friendly, general-purpose, great errors
One "morph" can convert between narrow ⇄ broad types which is surprisingly useful! Below some appetizers
MorphRow
Know parsers? MorphRow
simply always creates a printer alongside. Think
Email/Id/Time/Path/Url.fromString
⇄ Email/Id/Time/Path/Url.toString
Midi.fromBitList
⇄ Midi.toBitList
Building both in one is simpler and more reliable.
A 1:1 port of an example from elm/parser
:
import Morph exposing (MorphRow, broad, match, grab)
import List.Morph
import String.Morph
type Boolean
= BooleanTrue
| BooleanFalse
| BooleanOr { left : Boolean, right : Boolean }
boolean : MorphRow Boolean Char
boolean =
Morph.recursive "boolean"
(\step ->
Morph.choice
(\variantTrue variantFalse variantOr booleanChoice ->
case booleanChoice of
BooleanTrue ->
variantTrue ()
BooleanFalse ->
variantFalse ()
BooleanOr arguments ->
variantOr arguments
)
|> Morph.rowTry (\() -> BooleanTrue)
(String.Morph.only "true")
|> Morph.rowTry (\() -> BooleanFalse)
(String.Morph.only "false")
|> Morph.rowTry BooleanOr (or step)
|> Morph.choiceFinish
)
or : MorphRow Boolean Char -> MorphRow { left : Boolean, right : Boolean } Char
or step =
let
spaces : MorphRow (List ()) Char
spaces =
Morph.named "spaces"
(Morph.whilePossible (String.Morph.only " "))
in
Morph.narrow
(\left right -> { left = left, right = right })
|> match (String.Morph.only "(")
|> match (broad [] |> Morph.overRow spaces)
|> grab .left step
|> match (broad [ () ] |> Morph.overRow spaces)
|> match (String.Morph.only "||")
|> match (broad [ () ] |> Morph.overRow spaces)
|> grab .right step
|> match (broad [] |> Morph.overRow spaces)
|> match (String.Morph.only ")")
"((true || false) || false)"
|> Morph.toNarrow
(boolean
|> Morph.rowFinish
|> Morph.over List.Morph.string
)
--> Ok (BooleanOr { left = BooleanOr { left = BooleanTrue, right = BooleanFalse }, right = BooleanFalse })
What's different from writing a parser?
Morph.choice (\... -> case ... of ...)
matches possibilities exhaustivelygrab ... ...
also shows how to access the partbroad ...
provides a "default value" for the printerMorph also doesn't have loop
or a classic andThen
! Instead we have atLeast, between, exactly, optional, while possible, until next, until last, ...
This allows the quality of errors to be different to what you're used to. Here's a section of the example app:
MorphValue
Easily serialize from and to elm values independent of output format.
An example adapted from elm guide on custom types:
import Value.Morph exposing (MorphValue)
import Morph
import String.Morph
-- from lue-bird/elm-no-record-type-alias-constructor-function
import RecordWithoutConstructorFunction exposing (RecordWithoutConstructorFunction)
type User
= Anonymous
| SignedIn SignedIn
type alias SignedIn =
RecordWithoutConstructorFunction
{ name : String, status : String }
value : MorphValue User
value =
Morph.choice
(\variantAnonymous variantSignedIn user ->
case user of
Anonymous ->
variantAnonymous ()
SignedIn signedIn ->
variantSignedIn signedIn
)
|> Value.Morph.variant ( \() -> Anonymous, "Anonymous" ) Value.Morph.unit
|> Value.Morph.variant ( SignedIn, "SignedIn" ) signedInValue
|> Value.Morph.choiceFinish
signedInValue : MorphValue SignedIn
signedInValue =
Value.Morph.group
(\name status ->
{ name = name, status = status }
)
|> Value.Morph.part ( .name, "name" ) String.Morph.value
|> Value.Morph.part ( .statue, "status" ) String.Morph.value
|> Value.Morph.groupFinish
surprisingly easy and clean!
Morph.OneToOne
The simplest of them all: convert between any two types where nothing can fail. Think
List Bit
⇄ Bytes
, see List.Morph.bytes
Value
⇄ Json
– both just elm union type
s, see Json.Morph.value
Morph
The parent of MorphRow
, MorphValue
, Morph.OneToOne
etc.: convert between any two types. Think
Decimal
(just digits) ⇄ Float
with NaN and infinityAToZ
⇄ Char
, see AToZ.Morph.char
Confused? Hyped? Hit @lue up on anything on slack!
miniBill/elm-rope
allows our nested printer to still be O(n)
lambda-phi/parser
inspired MorphRow
's initial designzwilias/elm-bytes-parser
showed me how to convert a list of bits from and to Bytes
and gave me the courage to make MorphRow ... Bit
selm-verify-examples
and elm-review-documentation