indique/elm-pairdict/5.0.1

NOTE: the latest version is 6.0.3

PairDict

type PairDict left right

Want to look up value-pairs from the left or the right?

You want the left value of 🗝️ 1 and the right value of 🔑 0?

  → ( 🔑 0, 🗝️ 2 )
    ( 🔑 2, 🗝️ 0 )
    ( 🔑 1, 🗝️ 1 ) ←

Going through while checking, if your key is equal... Ah! Here they are:

    🔑 1 and 🗝️ 2

Like assoc-list, a PairDict allows for anything as left or right values except for functions and things that contain functions.

Example: cased letters

lowerUppercaseLetters=
  PairDict.empty
  |>PairDict.insert ( 'a', 'A' )
  |>PairDict.insert ( 'b', 'B' )
  |>PairDict.insert ( 'c', 'C' )


upperCase char=
  rightOf char lowerUppercaseLetters

create

empty : PairDict left right

A PairDict with no Pairs inside

fromDict : Dict left right -> PairDict left right

Create a PairDict from a association-Dict. left is the key, right is the value. If multiple equal keys or values are present, the value first in the Dict is prefered (see insert).

lowerToUpperLetters=
  AssocList.empty
  |>AssocList.insert 'a' 'A'
  |>AssocList.insert 'b' 'B'


lowerUpperLetters=
  PairDict.fromDict lowerToUpperLetters
fromList : List (Pair left right) -> PairDict left right

Create a PairDict conveniently from Pairs. If right or left values are given multiple times, the value first in the List is prefered (see insert).

PairDict.fromList
  [ ( 'b', 'B' ) --insert ( 'b', 'B' )
  , ( 'a', 'A' ) --insert ( 'a', 'A' )
  , ( 'b', 'C' ) --ignored, as the left value already exists
  , ( 'c', 'A' ) --ignored, as the right value already exists
  , ( 'c', 'C' ) --insert ( 'c', 'C' )
  ]
decode : Decoder left -> Decoder right -> Decoder (PairDict left right)

A Json.Decode.Decoder for PairDicts encoded by encodePair.

The order of insertion is not reconstructed (see equal)

"""
[
 {
  \"left\": 2,
  \"right\": 22
 },
 {
  \"left\": 1,
  \"right\": 11
 }
]
"""
|>Decode.decodeString
    (PairDict.decode
      Decode.int Decode.int
    )

Ok (Pairs [ ( 1, 11 ), ( 2, 22 ) ]) = a PairDict

scan

rightOf : left -> PairDict left right -> Maybe right

Just the right value if left is present in the PairDict, else Nothing

casedLetters=
  PairDict.empty
  |>PairDict.insert ( 'a', 'A' )
  |>PairDict.insert ( 'b', 'B' )


lowerCase char=
  leftOf char casedLetters
leftOf : right -> PairDict left right -> Maybe left

Just the left value if right is present in the PairDict, else Nothing

casedLetters=
  PairDict.empty
  |>PairDict.insert ( 'a', 'A' )
  |>PairDict.insert ( 'b', 'B' )


upperCase char=
  rightOf char casedLetters
equal : PairDict left right -> PairDict left right -> Bool

using (==) built-in equality is often not useful in the context of association-dicts.

Ignoring insertion order: do these 2 PairDicts have the same size and identical Pairs?

letterCodes=
  PairDict.fromList
    [ ( 'a', 97 ), ( 'b', 98 ) ]
fancyCompetingLetterCodes=
  PairDict.empty
  |>PairDict.insert ( 'b', 98 )
  |>PairDict.insert ( 'a', 97 )


PairDict.equal
  letterCodes
  fancyCompetingLetterCodes

True

{ ifEmpty : result
, ifMore : Pair left right -> PairDict left right -> result
}
-> PairDict left right
-> result

ifEmpty if the PairDict contains no Pairs, else ifMore with the most recently inserted Pair followed by a PairDict with the other Pairs.

It has a very similar use case to a case .. of on a List.

isEmpty=
  PairDict.emptyOrMore
    { ifEmpty= True
    , ifMore= \_ _-> False
    }
mostRecent=
  PairDict.emptyOrMore
    { ifMore= \pair _-> Just pair
    , ifEmpty= Nothing
    }
removeMostRecent=
  PairDict.emptyOrMore
    { ifMore= \_ rest-> rest
    , ifEmpty= PairDict.empty
    }
size : PairDict left right -> Int

How many Pairs there are in a PairDict.

PairDict.size empty

0

meaninglessNumbers=
  PairDict.fromList
    (List.map (\i-> ( i, i ))
      (List.range 0 41)
    )
PairDict.size meaninglessNumbers

42

in

insert : Pair left right -> PairDict left right -> PairDict left right

Put in a left-right-Pair.

If either value is already present, the PairDict is unchanged.

PairDict.empty
|>PairDict.insert ( 'b', 'B' )
    --puts it in 
|>PairDict.insert ( 'a', 'A' )
    --puts it in
|>PairDict.insert ( 'b', 'C' )
    --ignored, the left value already exists
|>PairDict.insert ( 'c', 'A' )
    --ignored, the right value already exists
|>PairDict.insert ( 'c', 'C' )
    --puts it in
union : PairDict left right -> PairDict left right -> PairDict left right

Combine 2 PairDicts, so that the Pairs in toInsert get inserted into preferred. If a value on the left or right is present, prefer the last PairDict (see insert).

numberNamedOperators=
  PairDict.fromList
    [ ( '+', "plus" )
    , ( '-', "minus" )
    ]
customNamedOperators=
  PairDict.fromList
    [ ( '∧', "and" )
    , ( '∨', "or" )
    , ( '-', "negate" )
    ]
validNamedOperators=
  PairDict.union
    custumNamedOperators --has a '-' left
    numberOperatorNames --preferred → its '-'-Pair is inserted

out

removeLeft : left -> PairDict left right -> PairDict left right

Remove the left-right Pair at left. If left does not exist, the PairDict is unchanged

PairDict.empty
|>PairDict.insert "(" ")"
|>PairDict.removeLeft ")" 
    --unchanged, ")" is not a left value
|>PairDict.removeLeft "("
    --removes ( "(", ")" )

PairDict.empty

removeRight : right -> PairDict left right -> PairDict left right

Remove the left-right Pair at right. If right does not exist, the PairDict is unchanged

PairDict.empty
|>PairDict.insert ( "(", ")" )
|>PairDict.removeRight "("
    --unchanged, "(" is not a right value
|>PairDict.removeRight ")"
    --removes ( "(", ")" )

PairDict.empty

shape

lefts : PairDict left right -> List left

Values on the left of all Pairs.

brackets=
  PairDict.fromList
    [ ( '(', ')' ), ( '{', '}' ) ]
opening= lefts brackets
rights : PairDict left right -> List right

Values on the right of all Pairs.

brackets=
  PairDict.fromList
    [ ( '(', ')' ), ( '{', '}' ) ]
closing= rights brackets
fold : (Pair left right -> acc -> acc) -> acc -> PairDict left right -> acc

Reduce the left-right Pairs from most recently inserted to least recently inserted.

A fold in the other direction doesn't exist, as association-Dicts should rarely rely on order (see equal).

brackets=
  PairDict.empty
  |>PairDict.insert ( '(', ')' )
  |>PairDict.insert ( '{', '}' )


openingAndClosing=
  brackets
  |>PairDict.fold
      (\( left, right ) acc->
        acc++[ String.fromList [ left, right ] ]
      )
      []

[ "{}", "()" ]

map :
(Pair left right -> Pair resultLeft resultRight)
-> PairDict left right
-> PairDict resultLeft resultRight

Map Pairs. Take a look at Pair's map operations.

digitNames=
  PairDict.empty
  |>PairDict.insert ( 0, "zero" )
  |>PairDict.insert ( 1, "one" )


mathSymbolNames=
  digitNames
  |>PairDict.map (Pair.mapLeft String.fromInt)
  |>PairDict.insert ( "+", "plus" )
toDict : PairDict left right -> Dict left right

Convert a PairDict to an association-Dict, which you can access only from the left.

casedLetters=
  PairDict.fromList
    [ ( 'A', 'a' ), ( 'B', 'b' ) ]
lowerFromUpper=
  PairDict.toDict casedLetters
encode : (left -> Value) -> (right -> Value) -> PairDict left right -> Value

Convert a PairDict to a Json.Encode.Value.

somePairDict=
  PairDict.empty
  |>PairDict.insert ( 1, 11 )
  |>PairDict.insert ( 2, 22 )
Encode.encode 1
  (PairDict.encode
    Encode.int Encode.int
    somePairDict
  )




"""
[
 {
  \"left\": 2,
  \"right\": 22
 },
 {
  \"left\": 1,
  \"right\": 11
 }
]
"""