lue-bird/elm-typesafe-array/1.0.0

NOTE: the latest version is 34.0.1

Arr

An Arr describes an array where you know more about the amount of elements.

Array.empty |> Array.get 0
--> Nothing


Arr.empty |> Arr.at nat0 FirstToLast
--> compile time error

Is this any useful? Let's look at an example:

0 to 100 joined by a space

joinBy between =
    \before after -> before ++ between ++ after


let
    intStringsAfter =
        Array.fromList (List.range 1 100)
            String.fromInt
in
Array.foldl (joinBy " ") "0" intStringsAfter
--> "0 1 2 3 4 5 ..."


Arr.nats nat100
    |> Arr.map (val >> String.fromInt)
    |> Arr.foldWith FirstToLast (joinBy " ")
--> "0 1 2 3 4 5 ..."

The Array version just seems hacky and is less readable. Arr simply knows more about the length at compile time, so you can e.g. call foldWith without a worry.

type alias Arr length element =
Typed Checked ArrTag Internal (Content length element)

An Arr describes an array where you know more about the amount of elements.

value / return types

  • amount >= 5
Arr (ValueMin Nat5) ...
  • 2 <= amount <= 12
Arr (ValueIn Nat2 Nat12) ...
  • = 4
Arr (ValueOnly Nat4) ...
  • the exact amount 3, also described as the difference between 2 numbers
Arr
    (ValueN Nat3
        (Nat3Plus more)
        (Is a To (Nat3Plus a))
        (Is b To (Nat3Plus b))
    )

function argument types

  • amount >= 4
Arr (In (Nat4Plus minMinus4) max maybeN) ...
  • 4 <= amount <= 15
Arr (In (Nat4Plus minMinus4) Nat15 maybeN) ...
  • = 15
Arr (Only Nat15) ...
  • any amount
Arr range ...

create

fromArray : Array element -> Arr (ValueMin Nat0) element

Create an Arr from an Array. As every Array has >= 0 elements:

Arr.fromArray arrayFromSomewhere
--> : Arr (ValueMin Nat0)


Arr.fromArray
    (Array.fromList [ 0, 1, 2, 3, 4, 5, 6 ])
--> big no


Arr.from7 0 1 2 3 4 5 6
--> ok


Arr.nats nat7
--> big yes

Tell the compiler if you know the amount of elements. Make sure the it knows as much as you!

repeat : Nat length -> element -> Arr length element

An Arr with a given amount of same elements.

Arr.repeat nat4 'L'
--> Arr.from4 'L' 'L' 'L' 'L'
--> : Arr (ValueN Nat4 ...) Char




Arr.repeat atLeast3 'L'
--> : Arr (ValueMin Nat3) Char
Nat
(In
(Nat1Plus minLengthMinus1)
(Nat1Plus maxLengthMinus1)
lengthMaybeN
)
-> Arr
(In
(Nat1Plus minLengthMinus1)
(Nat1Plus maxLengthMinus1)
lengthMaybeN
)
(Nat (ValueIn Nat0 maxLengthMinus1))

Increasing natural numbers. In the end, there are length numbers.

Arr.nats nat10
--> : Arr
-->     (ValueN Nat10 ...)
-->     (Nat (ValueIn Nat0 (Nat9Plus a)))


from first length_ =
    Arr.nats length_
        |> Arr.map (InNat.add first)
random : Nat length -> Generator element -> Generator (Arr length element)

Generate a given amount of elements and put them in an Arr.

exact

empty : Arr (ValueN Nat0 atLeast0 (Is a To a) (Is b To b)) element

No elements.

Arr.empty
--> : Arr (ValueN Nat0 ...) element
    |> NArr.push ":)"
--> : Arr (ValueN Nat1 ...) String
element
-> Arr
(ValueN
Nat1
(Nat1Plus more)
(Is a To (Nat1Plus a))
(Is b To (Nat1Plus b))
)
element

Create an Arr (ValueN Nat1 ...) from exactly 1 element in this order.

element
-> element
-> Arr
(ValueN
Nat2
(Nat2Plus more)
(Is a To (Nat2Plus a))
(Is b To (Nat2Plus b))
)
element

Create an Arr (ValueN Nat2 ...) from exactly 2 element in this order.

element
-> element
-> element
-> Arr
(ValueN
Nat3
(Nat3Plus more)
(Is a To (Nat3Plus a))
(Is b To (Nat3Plus b))
)
element

Create an Arr (ValueN Nat3 ...) from exactly 3 element in this order.

element
-> element
-> element
-> element
-> Arr
(ValueN
Nat4
(Nat4Plus more)
(Is a To (Nat4Plus a))
(Is b To (Nat4Plus b))
)
element

Create an Arr (ValueN Nat4 ...) from exactly 4 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat10
(Nat10Plus more)
(Is a To (Nat10Plus a))
(Is b To (Nat10Plus b))
)
element

Create an Arr (ValueN Nat10 ...) from exactly 10 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat11
(Nat11Plus more)
(Is a To (Nat11Plus a))
(Is b To (Nat11Plus b))
)
element

Create an Arr (ValueN Nat11 ...) from exactly 11 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat12
(Nat12Plus more)
(Is a To (Nat12Plus a))
(Is b To (Nat12Plus b))
)
element

Create an Arr (ValueN Nat12 ...) from exactly 12 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat13
(Nat13Plus more)
(Is a To (Nat13Plus a))
(Is b To (Nat13Plus b))
)
element

Create an Arr (ValueN Nat13 ...) from exactly 13 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat14
(Nat14Plus more)
(Is a To (Nat14Plus a))
(Is b To (Nat14Plus b))
)
element

Create an Arr (ValueN Nat14 ...) from exactly 14 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat15
(Nat15Plus more)
(Is a To (Nat15Plus a))
(Is b To (Nat15Plus b))
)
element

Create an Arr (ValueN Nat15 ...) from exactly 15 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat16
(Nat16Plus more)
(Is a To (Nat16Plus a))
(Is b To (Nat16Plus b))
)
element

Create an Arr (ValueN Nat16 ...) from exactly 16 element in this order.

element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat5
(Nat5Plus more)
(Is a To (Nat5Plus a))
(Is b To (Nat5Plus b))
)
element

Create an Arr (ValueN Nat5 ...) from exactly 5 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat6
(Nat6Plus more)
(Is a To (Nat6Plus a))
(Is b To (Nat6Plus b))
)
element

Create an Arr (ValueN Nat6 ...) from exactly 6 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat7
(Nat7Plus more)
(Is a To (Nat7Plus a))
(Is b To (Nat7Plus b))
)
element

Create an Arr (ValueN Nat7 ...) from exactly 7 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat8
(Nat8Plus more)
(Is a To (Nat8Plus a))
(Is b To (Nat8Plus b))
)
element

Create an Arr (ValueN Nat8 ...) from exactly 8 element in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr
(ValueN
Nat9
(Nat9Plus more)
(Is a To (Nat9Plus a))
(Is b To (Nat9Plus b))
)
element

Create an Arr (ValueN Nat9 ...) from exactly 9 element in this order.

scan

length : Arr length element -> Nat length

The amount of elements.

at :
Nat (In indexMin minMinus1 indexMaybeN)
-> LinearDirection
-> Arr (In (Nat1Plus minMinus1) max maybeN) element
-> element

Element at a valid position.

Arr.from3 1 2 3
    |> Arr.at nat1
--> 2

part

Nat (In minTaken maxTaken takenMaybeN)
-> Nat
(N
maxTaken
(Is a To atLeastMaxTaken)
(Is maxTakenToMin To min)
)
-> LinearDirection
-> Arr (In min max maybeN) element
-> Arr (In minTaken atLeastMaxTaken takenMaybeN) element

This works for both

Arr.from8 0 1 2 3 4 5 6 7
    |> Arr.take nat3 nat3 LastToFirst
--> Arr.from3 5 6 7


Arr.from8 0 1 2 3 4 5 6 7
    |> Arr.take between3To7 nat7 FirstToLast
--> : Arr (ValueIn Nat3 Nat7) ...
Nat (N dropped (Is minTaken To min) (Is maxTaken To max))
-> LinearDirection
-> Arr (In min max maybeN) element
-> Arr (ValueIn minTaken maxTaken) element

After a certain number of elements from one side.

with6To10Elements
    |> Arr.drop nat2 LastToFirst
--> : Arr (In Nat4 (Nat10Plus a)) ...

Use take LastToFirst if you know the exact amount of elements.

transform

map : (aElement -> bElement) -> Arr length aElement -> Arr length bElement

Change every element.

aToZ =
    Arr.nats nat26
        |> Arr.map
            ((+) ('a' |> Char.toCode)
                >> Char.fromCode
            )
LinearDirection
-> (element -> result -> result)
-> result
-> Arr (In min max maybeExact) element
-> result

Reduce an Arr in a direction.

Arr.from5 "l" "i" "v" "e"
    |> Arr.fold FirstToLast (++) ""
--> "live"


Arr.from5 "l" "i" "v" "e"
    |> Arr.fold LastToFirst (++) ""
--> "evil"
toArray : Arr length element -> Array element

Convert the Arr to an Array. Just do this in the end. Try to keep extra information as long as you can.

Arr.nats nat5
    |> Arr.map val
    |> Arr.toArray
--> Array.fromList [ 0, 1, 2, 3, 4 ]
(a -> b -> combined)
-> Arr length a
-> Arr length b
-> Arr length combined

Combine the elements of 2 Arrs to a new element. If one list is longer, the extra elements are dropped.

teamLifes aBoard bBoard =
    Arr.map2 (\a b -> a.lifes + b.lifes)
        aBoard
        bBoard
(a -> b -> c -> combinedElement)
-> Arr length a
-> Arr length b
-> Arr length c
-> Arr length combinedElement

Works like map2.

(a -> b -> c -> d -> combinedElement)
-> Arr length a
-> Arr length b
-> Arr length c
-> Arr length d
-> Arr length combinedElement

Works like map2.

LinearDirection
-> (element -> element -> element)
-> Arr (In (Nat1Plus minMinus1) max maybeN) element
-> element

A fold where the initial result is the first value.

Arr.foldWith FirstToLast maximum
    (Arr.from3 234 345 543)
--> 543
reverse : Arr length element -> Arr length element

Flip the order of the elements.

Arr.from5 "l" "i" "v" "e"
    |> Arr.reverse
--> Arr.from5 "e" "v" "i" "l"

modify

Nat (In indexMin minLengthMinus1 indexMaybeN)
-> LinearDirection
-> element
-> Arr (In (Nat1Plus minLengthMinus1) max maybeN) element
-> Arr (In (Nat1Plus minLengthMinus1) max maybeN) element

Set the element at an index in a direction.

Arr.from3 "I" "am" "ok"
    |> Arr.replaceAt nat2 FirstToLast "confusion"
--> Arr.from3 "I" "am" "confusion"


Arr.from3 "I" "am" "ok"
    |> Arr.replaceAt nat1 LastToFirst "feel"
--> Arr.from3 "I" "feel" "ok"

drop information

Nat (In lowerMin min lowerMaybeN)
-> Arr (In min max maybeN) element
-> Arr (ValueIn lowerMin max) element

Use a lower minimum length in the type.

[ atLeast3Elements
, atLeast4Elements
]

Elm complains:

But all the previous elements in the list are Arr (ValueMin Nat3) ...

[ atLeast3Elements
, atLeast4Elements
    |> Arr.lowerMinLength nat3
]

restore information

Nat (N max (Is a To atLeastMax) x)
-> Arr (In min max maybeN) element
-> Arr (In min atLeastMax maybeN) element

Make an Arr with a fixed maximum length fit into functions with require a higher maximum length.

While designing argument annotations as general as possible:

atMost18Elements : Arr (In min Nat18 maybeN) ...

The argument in atMost18Elements should also fit in atMost19Elements.

atMost19Elements theArgument
--> error :(


atMost19Elements
    (theArgument |> Arr.restoreMaxLength nat18)
--> works
Nat (ValueN n atLeastN aDifference bDifference)
-> Arr (Only n maybeN) element
-> Arr (ValueN n atLeastN aDifference bDifference) element

Transform a potential ValueOnly Arr to a ValueN.

append10s :
    Arr (Only Nat10 aMaybeN) element
    -> Arr (Only Nat10 bMaybeN) element
    -> Arr (ValueN Nat20 (Nat20Plus a) ...)
append10s a10Elements b10Elements =
    a10Elements
        |> InArr.extend nat10 nat10 b10Elements
        |> Arr.restoreLength nat20

extra

Nat length
-> Codec String element
-> Codec String (Arr length element)

A Codec to serialize Arrs with a specific amount of elements.

import Serialize




-- we can't start if we have no worlds to choose from!
serializeGameRow :
    Serialize.Codec
        String
        (Arr (ValueN Nat10 ...) GameField)
serializeGameRow =
    Arr.serialize nat10 serializeGameField


encode : Arr (Only Nat10 maybeN) GameField -> Bytes
encode =
    Arr.restoreLength nat10
        >> Serialize.encodeToBytes serializeGameRow


decode :
    Bytes
    ->
        Result
            (Serialize.Error String)
            (Arr (ValueN Nat10 ...) GameField)
decode =
    Serialize.decodeFromBytes serializeGameRow