jmpavlick / bimap / Bimap

Bidirectional mapping/comparison/JSON (en,de)coding between Strings and types.


type Bimap a

A bidirectional map between a String and a custom type.

init : match -> Builder match v

Initializes a Bimap. You will need to pass a pattern-matching function with one parameter per variant, plus an extra parameter for the "value".

type Response
    = Yes
    | No

bimap : Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build

variant : String -> v -> Builder (String -> b) v -> Builder b v

Adds a map between a String and a value of your custom type.

... -- a pattern-matching function goes before the variants
|> Bimap.variant "Yes" Yes
|> Bimap.variant "No" No
... -- a call to Bimap.build goes after

build : Builder (a -> String) a -> Bimap a

Resolves your maps and pattern-matching function into a Bimap that you can use.

... -- calls to Bimap.variant go before the call to Bimap.build
|> Bimap.build

fromString : Bimap a -> String -> Maybe a

Returns the mapped custom type value for a given String, if the String has been mapped.

type Response
    = Yes
    | No

bimap : Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build


Bimap.fromString bimap "Yes" --> Yes
Bimap.fromString bimap "Maybe" --> Nothing

toString : Bimap a -> a -> String

Returns the mapped String for a given custom type value.

type Response
    = Yes
    | No

bimap :
    Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build


Bimap.toString No --> "No"

values : Bimap a -> List ( String, a )

Returns a List of tuples of all String keys and custom type values, in the same order that they were added.

type Response
    = Yes
    | No

bimap : Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build


Bimap.values bimap -- [ ( "Yes", Yes ), ( "No", No ) ]

toIndex : Bimap a -> a -> Basics.Int

Returns the Int index of a custom type value. Values are indexed in the same order that they were added.

type Response
    = Yes
    | No


bimap : Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build

Bimap.toIndex bimap Yes -- 0
Bimap.toIndex bimap No -- 1

fromIndex : Bimap a -> Basics.Int -> Maybe a

Returns Just a for a custom type value at a given Int index, if one exists; Nothing otherwise. Values are indexed in the same order that they were added.

type Response
    = Yes
    | No


bimap : Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build

Bimap.fromIndex bimap 0 -- Just Yes
Bimap.fromIndex bimap 1 -- Just No
Bimap.fromIndex bimap 2 -- Nothing

compare : Bimap a -> a -> a -> Basics.Order

Compares two custom type values in a Bimap. Very useful for sorting when partially applied and passed to List.sortWith.

type Response
    = Yes
    | No


bimap : Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build

sort : List Response -> List Response
sort =
    List.sortWith (Bimap.compare bimap)


sort [ No, Yes ] -- [ Yes, No ]

decoder : Bimap a -> Json.Decode.Decoder a

Decoder for a custom type value in a Bimap.

import Json.Decode as Decode exposing (Decoder)

type Response
    = Yes
    | No


bimap : Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build

decoder : Decoder Response
decoder =
    Bimap.decoder bimap

okJson : String
okJson =
    """{ "response": "Yes" }"""

badJson : String
badJson =
    """{ "response": "Maybe" }"""

jsonDecoder : Decoder Response
jsonDecoder =
    Decode.field "response" decoder

Decode.decodeString jsonDecoder okJson -- Ok Yes
Decode.decodeString jsonDecoder badJson -- Err (Field "number" (Failure "Decode failed; Six is not a valid value. Expected one of: One; Two; Three" <internals>))


sort [ No, Yes ] -- [ Yes, No ]

encoder : Bimap a -> a -> Json.Encode.Value

Encoder for a custom type value in a Bimap.

import Json.Encode as Encode

type Response
    = Yes
    | No


bimap : Bimap Response
bimap =
    Bimap.init
        (\yes no value ->
            case value of
                Yes ->
                    yes

                No ->
                    no
        )
        |> Bimap.variant "Yes" Yes
        |> Bimap.variant "No" No
        |> Bimap.build


encoder : Response -> Encode.Value
encoder =
    Bimap.encoder bimap

Encoder.encode 0 (encoder Yes) -- "\"Yes\""