lue-bird/elm-morph/3.0.1

List.Morph

MorphIndependently
(beforeToNarrow -> Result (ErrorWithDeadEnd deadEnd) narrow)
(beforeToBroad -> broad)
-> MorphIndependently
( List beforeToNarrow
-> Result (ErrorWithDeadEnd deadEnd) (List narrow)
)
(List beforeToBroad -> List broad)

Morph all elements. On the narrowing side all narrowed values must be Ok for it to not result in a Morph.Error

If the element Morph is OneToOne, each will always succeed with the type knowing it does

sequence

(element -> MorphRow narrow broadElement)
-> List element
-> MorphRow (List narrow) broadElement

From the elements in a given List, create MorphRows that will be run in the same order, one after the other.

Some also call this "traverse" (or "for" when the arguments are flipped)

import Morph exposing (MorphRow)
import String.Morph
import AToZ


"helloTHEREcooorwhat"
    |> Morph.toNarrow
        (List.Morph.sequenceMap casedStringOnly [ "hello", "there", "coo", "or", "what" ]
            |> Morph.rowFinish
            |> Morph.over List.Morph.string
        )
--> Ok [ AToZ.CaseLower, AToZ.CaseUpper, AToZ.CaseLower, AToZ.CaseLower, AToZ.CaseLower ]


casedStringOnly : String -> MorphRow AToZ.Case Char
casedStringOnly string =
    Morph.choice
        (\lower upper cased ->
            case cased of
                AToZ.CaseLower -> lower ()
                AToZ.CaseUpper -> upper ()
        )
        |> Morph.rowTry (\() -> AToZ.CaseLower)
            (String.Morph.only (string |> String.toLower))
        |> Morph.rowTry (\() -> AToZ.CaseUpper)
            (String.Morph.only (string |> String.toUpper))
        |> Morph.choiceFinish

Don't try to be clever with this.

The usual Morph.narrow(\... -> ...) |>grab-match chain is often more explicit, descriptive and type-safe.

Because of this, List.Morph only exposes sequenceMap, not sequence, making misuse a bit more obvious.

If each element's MorphRow will always produce the same broad value like String.Morph.only, use broadSequenceMap

(element -> MorphRow () broadElement)
-> List element
-> MorphRow () broadElement

Match broad MorphRows (those that can always produce the same broad value) based on given input elements in sequence.

This can get verbose, so create helpers with it where you see common patterns!

import Morph exposing (MorphRow)
import Char.Morph
import List.Morph


textOnly : String -> MorphRow () Char
textOnly stringConstant =
    List.Morph.broadSequenceMap
        (Char.Morph.only >> Morph.one)
        (stringConstant |> String.toList)


-- Match a specific character, case sensitive
"abc"
    |> Morph.toNarrow
        (textOnly "abc" |> Morph.rowFinish |> Morph.over List.Morph.string)
--> Ok ()


-- It fails if it's not _exactly_ the same
"abC"
    |> Morph.toNarrow
        (textOnly "abc" |> Morph.rowFinish |> Morph.over List.Morph.string)
    |> Result.toMaybe
--> Nothing

Note that textOnly is available as String.Morph.only. Others aren't, tho, like when matching only a specific sequence of Bits

transform

MorphIndependently
( Emptiable (Stacked broadElement) Possibly
-> Result error_ (List broadElement)
)
( List narrowElement
-> Emptiable (Stacked narrowElement) Possibly
)

Morph.OneToOne from a stack

import Stack
import Morph


Stack.topBelow 0 [ 12, 3 ]
    |> Morph.mapTo List.Morph.stack
--> [ 0, 12, 3 ]

Inverse of Stack.Morph.list

MorphIndependently
(Array narrowElement -> Result error_ (List narrowElement))
(List element -> Array element)

Morph.OneToOne from an Array

import Array
import Morph


Array.fromList [ 0, 1, 2, 3 ]
    |> Morph.mapTo List.Morph.array
--> [ 0, 1, 2, 3 ]

Inverse of Array.Morph.list

MorphIndependently
( ArraySized narrowElement narrowRange_
-> Result error_ (List narrowElement)
)
( List broadElement
-> ArraySized broadElement (Min (Up0 broadX_))
)

Morph.OneToOne from an ArraySized

import ArraySized
import Morph


ArraySized.l4 0 1 2 3
    |> Morph.mapTo List.Morph.arraySized
--> [ 0, 1, 2, 3 ]

Inverse of ArraySized.Morph.list

string : MorphOrError (List Char) String error_

Morph.OneToOne from a String to a List Char.

Inverse of String.Morph.list

set :
MorphIndependently
(Set narrowElement -> Result error_ (List narrowElement))
(List comparableBroadElement -> Set comparableBroadElement)

Morph.OneToOne from a Set

import Set
import Morph


Set.fromList [ 0, 1, 2, 3 ]
    |> Morph.mapTo List.Morph.set
--> [ 0, 1, 2, 3 ]

Inverse of Set.Morph.list

MorphIndependently
( Dict broadKey broadValue
-> Result
error_
(List
{ key : broadKey
, value : broadValue
}
)
)
( List
{ key : comparableNarrowKey
, value : narrowValue
}
-> Dict comparableNarrowKey narrowValue
)

Morph.OneToOne from a Dict key value to a List { key : key, value : value }.

import Dict
import List.Morph
import Morph


Dict.empty
    |> Dict.insert 0 'a'
    |> Dict.insert 1 'b'
    |> Morph.mapTo List.Morph.dict
--> [ { key = 0, value = 'a' }, { key = 1, value = 'b' } ]

Inverse of Dict.Morph.list

bytes : MorphOrError (Emptiable (Stacked Bit) Possibly) Bytes error_

Morph.OneToOne from Bytes to a list of individual bits. Now you can morph them as a row!

value : MorphValue element -> MorphValue (List element)