lue-bird/elm-typesafe-array/3.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.

types

  • amount >= 5
Arr (Min Nat5) ...
  • 2 <= amount <= 12
Arr (In Nat2 Nat12) ...
  • = 4
Arr (Only Nat4) ...

as argument types

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

create

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

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

Arr.fromArray arrayFromSomewhere
--> : Arr (Min 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 (ArgIn min max maybeN) -> element -> Arr (In min max) element

An Arr with a given amount of same elements.

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




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

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

Arr.nats nat10
--> : Arr
-->     (N Nat10 ...)
-->     (Nat (In 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 (Only Nat0) element

No elements.

Arr.empty
--> : Arr (Only Nat0) element
    |> NArr.push ":)"
--> : Arr (Only Nat1) String
from1 : element -> Arr (Only Nat1) element

Create an Arr (Only Nat1) from exactly 1 elements in this order.

from2 : element -> element -> Arr (Only Nat2) element

Create an Arr (Only Nat2) from exactly 2 elements in this order.

from3 : element -> element -> element -> Arr (Only Nat3) element

Create an Arr (Only Nat3) from exactly 3 elements in this order.

from4 : element -> element -> element -> element -> Arr (Only Nat4) element

Create an Arr (Only Nat4) from exactly 4 elements in this order.

element
-> element
-> element
-> element
-> element
-> Arr (Only Nat5) element

Create an Arr (Only Nat5) from exactly 5 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat6) element

Create an Arr (Only Nat6) from exactly 6 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat7) element

Create an Arr (Only Nat7) from exactly 7 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat8) element

Create an Arr (Only Nat8) from exactly 8 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat9) element

Create an Arr (Only Nat9) from exactly 9 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat10) element

Create an Arr (Only Nat10) from exactly 10 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat11) element

Create an Arr (Only Nat11) from exactly 11 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat12) element

Create an Arr (Only Nat12) from exactly 12 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat13) element

Create an Arr (Only Nat13) from exactly 13 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat14) element

Create an Arr (Only Nat14) from exactly 14 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat15) element

Create an Arr (Only Nat15) from exactly 15 elements in this order.

element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> element
-> Arr (Only Nat16) element

Create an Arr (Only Nat16) from exactly 16 elements in this order.

scan

length : Arr length element -> Nat length

The amount of elements.

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

Element at a valid position.

Arr.from4 1 2 3 4
    |> Arr.at nat1 FirstToLast
--> 2


Arr.from4 1 2 3 4
    |> Arr.at nat1 LastToFirst
--> 3

part

Nat (ArgIn minTaken maxTaken takenMaybeN)
-> Nat
(ArgN
maxTaken
(Is a To atLeastMaxTaken)
(Is maxTakenToMin To min)
)
-> LinearDirection
-> Arr (In min max) element
-> Arr (In minTaken atLeastMaxTaken) 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 (In Nat3 Nat7) ...
Nat (ArgN dropped (Is minTaken To min) (Is maxTaken To max))
-> LinearDirection
-> Arr (In min max) element
-> Arr (In 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
            (val >> fromPositionInABC)


fromPositionInABC =
    (+) ('a' |> Char.toCode)
        >> Char.fromCode

val refers to Typed.val.

LinearDirection
-> (element -> result -> result)
-> result
-> Arr (In min max) 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 ]
LinearDirection
-> (element -> element -> element)
-> Arr (In (Nat1Plus minMinus1) max) 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"
Nat
(ArgIn
(Nat1Plus minGroupSizMinus1)
maxGroupSize
groupSizeMaybeN
)
-> LinearDirection
-> Arr (In min max) element
-> { groups :
Arr
(In Nat0 max)
(Arr
(ArgIn
(Nat1Plus minGroupSizMinus1)
maxGroupSize
groupSizeMaybeN
)
element
)
, less : Arr (In Nat0 maxGroupSize) element
}

Split the Arr into equal-sized chunks.

{ groups : the Arr divided into equal-sized Arrs
, less : values to one side which aren't enough
}


Arr.from7 1 2 3 4 5 6 7
    |> MinArr.groupsOf nat5 FirstToLast
--> { groups = Arr.from1 (Arr.from5 1 2 3 4 5)
--> , less = Arr.from2 6 7
--> }

The type of the result isn't as accurate as in the example, though!

map

(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

The length pf all Arrs must be in the same range.

  • If 1 Arr is a potential Arr (Min ...), you have to
Arr.map2 (\a b -> a.lifes + b.lifes)
    (aBoard |> MinArr.value)
    (bBoard |> MinArr.value)

aBoard, bBoard : Arr (In Nat2 someMax) Field

for every non-Arr (Min ...).

  • If 1 Arr has a higher minimum length, you have to
Arr.map2 (\a b -> a.lifes + b.lifes)
    (aBoard |> Arr.lowerMinLength nat2)
    bBoard

aBoard : Arr (In Nat5 Nat10) Field
(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.

modify

Nat (ArgIn indexMin minLengthMinus1 indexMaybeN)
-> LinearDirection
-> element
-> Arr (In (Nat1Plus minLengthMinus1) max) element
-> Arr (In (Nat1Plus minLengthMinus1) max) 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 (ArgIn lowerMin min lowerMaybeN)
-> Arr (In min max) element
-> Arr (In 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 (Min Nat3) ...

[ atLeast3Elements
, atLeast4Elements
    |> Arr.lowerMinLength nat3
]

restore information

Nat (ArgN max (Is a To atLeastMax) x)
-> Arr (In min max) element
-> Arr (In min atLeastMax) 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) ...

The argument in atMost18Elements should also fit in atMost19Elements.

atMost19Elements theArgument
--> error :(


atMost19Elements
    (theArgument |> Arr.restoreMaxLength nat18)
--> works

extra

Nat (ArgIn min max maybeN)
-> Codec String element
-> Codec String (Arr (In min max) 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 (Only Nat10) GameField)
serializeGameRow =
    Arr.serialize nat10 serializeGameField


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


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