lue-bird/elm-keysset/3.0.0

NOTE: the latest version is 5.0.2

Keys

Multiple key Orderings

Configure what's considered a key inside a KeysSet

Create starting with Keys.for and building with |> Keys.by as shown in the readme examples

You can just ignore the Typed thing but if you're curious → typed-value

type alias Keys element keys keyCount =
KeysBeingBuilt element keys keys (On keyCount)

The type of fully constructed KeysBeingBuilt ready to use.

"infer types" is your friend here

import Keys exposing (Keys, Key)
import Order
import Char.Order
import String.Order
import Emptiable
import N exposing (Up, To, N0, N1, N2)


userKeys :
    -- just infer this
    Keys
        User
        { name :
            Key
                User
                (Order.By
                    User.Name
                    (String.Order.Earlier (Char.Order.Alphabetically Order.Tie))
                )
                String
                (Up N1 To N1)
        , email : Key User (Order.By User.Email Email.DefaultOrder) String (Up N0 To N1)
        }
        N2
userKeys =
    Keys.for (\name email -> { name = name, email = email } )
        |> Keys.by ( .name, User.name )
            (String.Order.earlier (Char.Order.alphabetically Order.tie))
        |> Keys.by ( .email, User.email )
            Email.defaultOrder


Emptiable.empty
    |> KeysSet.insert userKeys
        { username = "ben", email = [email protected].. }
    |> KeysSet.insert userKeys
        { username = "mai", email = [email protected].. }
    -- not inserted
    -- There's already an element where .email is [email protected]..

What's with those Up N.. To N..? Internally, each key will be assigned an index. that type from bounded-nat preserves the knowledge that each key's index is less than the whole count.

type KeysTag

Tags correctly constructed Keys (and each Key)

type alias Key element orderByTag key index =
Typed
Checked
( KeysTag, orderByTag )
Public
{ index : N (Exactly index)
, toKey : element -> key
, keyOrder : ( key, key ) -> Order
}

By which aspect = key and in which key Order elements should be sorted

create

Ordering element elementOrderTag
-> Identity element elementOrderTag

Ordering by the element itself.

Short for

Keys.identity order =
    for identity |> by ( identity, Map.identity ) order

in KeysSet

import Map
import Order
import Int.Order
import N exposing (Up, To, N0)
import KeysSet


intIncreasing : Keys.Identity Int Int.Order.Increasing
intIncreasing =
    Keys.identity Int.Order.increasing


KeysSet.fromList intIncreasing [ -1, 5, 5, 8, 7 ]
    |> KeysSet.toList ( intIncreasing, Basics.identity )
--> [ -1, 5, 7, 8 ]
type alias Identity element elementOrderTag =
Keys
element
(Key
element
(By Identity elementOrderTag)
element
(Up N0 To N0)
)
N1

Resulting type of Keys.identity.

import Map
import Order
import Float.Order
import N exposing (Up, To, N0)
import KeysSet


floatIncreasing : Keys.Identity Float Float.Order.Increasing
floatIncreasing =
    Keys.identity Float.Order.increasing


KeysSet.fromList floatIncreasing [ -1.1, 5, 5, 8.7, 7.8 ]
    |> KeysSet.toList ( floatIncreasing, Basics.identity )
--> [ -1.1, 5, 7.8, 8.7 ]
for :
keysConstructor
-> KeysBeingBuilt element_ completeKeys_ keysConstructor (Up0 x_)

Start a keys builder by giving names to the individual keys as arguments using a record

userKeys :
    Keys
        User
        { email : Key User (Order.By User.Email Email.Order) Email (Up N0 To N0) }
        N1
userKeys =
    Keys.for (\email -> { email = email })
        |> Keys.by ( .email, User.email, Email.order )


Emptiable.empty
    |> KeysSet.insert userKeys
        { name = "ben", email = "[email protected]" }
    |> KeysSet.insert userKeys
        { name = "mai", email = "[email protected]" }
    -- not inserted
    -- There's already an element where .email is "[email protected]"
type alias KeysBeingBuilt element keysComplete keysConstructor keyCount =
Typed
Checked
Internal
{ keys : keysConstructor
, toArray :
ArraySized
(keysComplete -> ( element, element ) -> Order)
(Exactly keyCount)
}

Once you supply all the necessary key-Orderings with by, a KeysBeingBuilt is automatically of type Keys.

So if you for example infer the type

KeysBeingBuilt element { yourKeys } { yourKeys } keyCount

you can replace it by

Keys element { yourKeys } keyCount

It's data is unaccessible because you shouldn't be able to

  • retrieve it's keys to use in different Keys
  • have an out of sync array representation
by :
( keysComplete
-> Key
element
(By toKeyTag keyOrderTag)
key
(Up indexToLast To lastIndex)
, Mapping element toKeyTag key
)
-> Ordering key keyOrderTag
-> KeysBeingBuilt
element
keysComplete
( Key
element
(By toKeyTag keyOrderTag)
key
(Up indexToLast To lastIndex)
-> keysConstructedPartially
)
(Up (Add1 indexToLast) To (Add1 lastIndex))
-> KeysBeingBuilt
element
keysComplete
keysConstructedPartially
(Up indexToLast To (Add1 lastIndex))

Add a key

  • what name does the key have? (same as in the initial record from Keys.for)
  • which aspect should be sorted by? → Mapping
  • how should we compare these aspects? Ordering

safe internals

You won't need them if you just want to use KeysSet. ... It's safe to expose this information, tho, so why not make it available :)

transform

Keys element keys_ keyCount
-> ArraySized
(( element, element ) -> Order)
(Exactly (On keyCount))

List all keys in the keys record as an array of functions determining the Order of 2 elements

single key

( Keys element keys (Add1 lastIndex)
, keys -> Key element by_ key (Up indexToLast_ To lastIndex)
)
-> element
-> key

How to turn the element into the specified key

( Keys element keys (Add1 lastIndex)
, keys -> Key element by_ key (Up indexToLast_ To lastIndex)
)
-> ( key, key )
-> Order

How to order by the specified key

( Keys element keys (Add1 lastIndex)
, keys -> Key element key_ by_ (Up indexToLast To lastIndex)
)
-> N (Exactly (Up indexToLast To lastIndex))

A Key's distance from the first by in the Keys builder