An Array that knows more about the amount of elements it holds
import Linear exposing (Direction(..))
import N exposing (n0)
import Array
Array.empty |> Array.get 0
--> Nothing
ArraySized.empty |> ArraySized.element ( Up, n0 )
-- compile-time errorIs this any useful? One example:
You have an array of 1+ elements. What's its greatest value?
withArray : Array comparable -> Maybe comparable
withArray =
Array.foldl
(\element soFar ->
case soFar of
Just maxSoFar ->
max maxSoFar element
Nothing ->
element
)
Nothing
withArraySized :
ArraySized comparable (In (On (Add1 minFrom1_)) max_)
-> comparable
withArraySized =
ArraySized.fold Up Basics.maxThe Array type can't express it contains 1+ elements.
ArraySized knows about its length at compile time,
so we can fold, access, ... without a worry
A given amount of same elements
import N exposing (n4)
ArraySized.repeat 'L' n4
--: ArraySized Char (In (Up4 minX_) (Up4 maxX_))
|> ArraySized.toList
--> [ 'L', 'L', 'L', 'L' ]
ArraySized.repeat 'L' atLeast3
--: Char ArraySized (Min (Up3 x_))Increasing natural numbers until including a given number
import N exposing (n3, n0)
ArraySized.upTo n3
--: ArraySized
--: (N (In (Up0 minX_) (Up3 maxX_)))
--: (In (On N4) (Up4 maxX_))
|> ArraySized.map N.toInt
|> ArraySized.toList
--> [ 0, 1, 2, 3 ]
ArraySized.upTo n0
--: ArraySized
--: (N (In (Up0 minX_) (Up0 maxX_)))
--: (In (On N1) (Up1 maxX_))
|> ArraySized.map N.toInt
|> ArraySized.toList
--> [ 0 ]
ArraySized.upTo between2And9
|> ArraySized.map (N.add n3)
--: ArraySized
--: (N (In (Up5 minX_) (Up12 maxX_)))
--: (In (On N3) (Up10 maxX_))To turn the On length minimum into a difference (for results etc.)
→ minTo
Random.Generator for a given amount of random elements
import N exposing (n5)
ArraySized.random (Random.float 0 1) n5
--: Random.Generator
--: (ArraySized
--: Float
--: (In (Up5 minX_) (Up5 maxX_))
--: )Pairs really well with
N.randomIn ( <length min>, <length max> )
|> Random.andThen
(ArraySized.random <element>)Fuzzer for an ArraySized with a given length
import N exposing (n3)
import Fuzz
ArraySized.fuzz Fuzz.bool n3
|> Fuzz.map ArraySized.toList
--: Fuzzer (ArraySized Bool (In (Up3 minX_) (Up6 maxX_)))
|> Fuzz.examples 3
--> [ [ False, True, False ]
--> , [ False, False, False ]
--> , [ False, False, True ]
--> ]To fuzz an ArraySized with a length in a range, inFuzz
Fuzzer for an ArraySized with a length in a given range.
For larger ranges, smaller lengths are preferred
import N exposing (n3, n6)
import Fuzz
ArraySized.inFuzz Fuzz.bool ( n3, n6 )
|> Fuzz.map ArraySized.toList
--: Fuzzer (ArraySized Bool (In (Up3 minX_) (Up6 maxX_)))
|> Fuzz.examples 3
--> [ [ False, True, False, False, True, True ]
--> , [ False, False, False, True ]
--> , [ False, True, False, False, False, False ]
--> ]Create from an Array.
As every Array has >= 0 elements
arrayFromSomeOtherLibrary |> ArraySized.fromArray
--: ArraySized ... (Min (Up0 x_))Don't use it for construction
ArraySized.fromArray
(Array.fromList [ 0, 1, 2, 3, 4, 5, 6 ])
-- big noMake sure the compiler knows as much as you about the amount of elements!
ArraySized.l7 0 1 2 3 4 5 6 -- ok
ArraySized.upTo n6 -- big yesCreate from a List.
As every List has >= 0 elements
listFromSomeOtherLibrary |> ArraySized.fromList
--: ArraySized ... (Min (Up0 x_))Don't use for construction
ArraySized.fromList [ 0, 1, 2, 3, 4, 5, 6 ]
-- big no!Make sure the compiler knows as much as you about the amount of elements!
ArraySized.l7 0 1 2 3 4 5 6 -- ok
ArraySized.upTo n6 -- big yesOn Emptiable.filled ArraySized.one,
on Emptiable.empty ArraySized.empty
import N exposing (n0)
import Emptiable exposing (filled)
filled "hi"
|> ArraySized.fromEmptiable
--: ArraySized ... (In (Up0 minX_) (Up1 maxX_))
|> ArraySized.toList
--> [ "hi" ]
Emptiable.empty
|> ArraySized.fromEmptiable
--: ArraySized ... (In (Up0 minX_) (Up1 maxX_))
|> ArraySized.toList
--> []Emptiness knowledge possiblyOrNever is transferred
Create from a stack.
As every stack has >= 0 elements
Emptiable.empty |> ArraySized.fromStack
--: ArraySized ... (Min (On N0))
Stack.topBelow '#' [] |> ArraySized.fromStack
--: ArraySized Char (Min (On N1))Don't use for construction
ArraySized.fromStackEmptiable
(Stack.fromList [ 0, 1, 2, 3, 4, 5, 6 ])
-- big no!Make sure the compiler knows as much as you about the amount of elements!
ArraySized.l7 0 1 2 3 4 5 6 -- ok
ArraySized.upTo n6 -- big yesCreate from the Chars of a String.
As every String has >= 0 elements
stringFromSomeOtherLibrary |> ArraySized.fromString
--: ArraySized Char (Min (Up0 minX_))Try not to use this for construction
and instead use the safe versions like l<n>
No elements
ArraySized.empty
--: ArraySized element_ (In (Up0 minX_) (Up0 maxX_))
|> ArraySized.push ":)"
--: ArraySized String (In (Up1 minX_) (Up1 maxX_))Create with only 1 single given element
Create with 2 given elements in the order they are supplied
Create with 3 given elements in the order they are supplied
Create with 4 given elements in the order they are supplied
Create with 5 given elements in the order they are supplied
Create with 6 given elements in the order they are supplied
Create with 7 given elements in the order they are supplied
Create with 8 given elements in the order they are supplied
Create with 9 given elements in the order they are supplied
Create with 10 given elements in the order they are supplied
Create with 11 given elements in the order they are supplied
Create with 12 given elements in the order they are supplied
Create with 13 given elements in the order they are supplied
Create with 14 given elements in the order they are supplied
Create with 15 given elements in the order they are supplied
Create with 16 given elements in the order they are supplied
You can generate l<n> with n >= 17 locally,
put them in a module ArraySized.Local exposing (l<n>, ...) + import ArraySized.Local as ArraySized
Its amount of elements
import N exposing (n3)
ArraySized.l3 1 2 3
|> ArraySized.length
--: N (In (Up3 minX_) (Up3 maxX_))
|> N.toInt
--> 3
between3And5Elements |> ArraySized.length
--: N (In (Up3 minX_) (Up5 maxX_))
atLeast3Elements |> ArraySized.length
--: N (Min (Up3 minX_))Its element at a valid location
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n1)
ArraySized.l4 0 1 2 3
|> ArraySized.element ( Up, n1 )
--> 1
ArraySized.l4 0 1 2 3
|> ArraySized.element ( Down, n1 )
--> 2Its element at a given location
in a given Direction.
Because the index doesn't promise it's <= the ArraySized's length minimum,
elementTry gives back an Emptiable
Use element if you know your index always points to a valid location
import Linear exposing (Direction(..))
import Emptiable
import N exposing (n1, n5)
ArraySized.l4 0 1 2 3
|> ArraySized.elementTry ( Up, n5 )
--> Emptiable.empty
ArraySized.l4 0 1 2 3
|> ArraySized.elementTry ( Down, n1 )
--> Emptiable.filled 2Its one and only, first and last element
ArraySized.one "hi" |> ArraySized.toOne
--> "hi"Searching for all, any? → allFill
Set the element at an index
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n1, n2)
ArraySized.l3 "I" "am" "ok"
|> ArraySized.elementReplace ( Up, n2 )
(\() -> "confusion")
|> ArraySized.toList
--> [ "I", "am", "confusion" ]
ArraySized.l3 "I" "am" "ok"
|> ArraySized.elementReplace ( Down, n1 )
(\() -> "feel")
|> ArraySized.toList
--> [ "I", "feel", "ok" ]An index that's too high to point to an existing element is ignored and no element is replaced
import Linear exposing (Direction(..))
import N exposing (n3)
ArraySized.l3 "I" "am" "ok"
|> ArraySized.elementReplace ( Down, n3 )
(\() -> "feel")
|> ArraySized.toList
--> [ "I", "am", "ok" ]Change the element at an index
in a given Direction
based on its previous value
import Linear exposing (Direction(..))
import N exposing (n0)
ArraySized.l3 1 20 30
|> ArraySized.elementAlter ( Up, n0 ) (\x -> x * 10)
|> ArraySized.toList
--> [ 10, 20, 30 ]
ArraySized.l3 1 20 30
|> ArraySized.elementAlter ( Down, n0 ) negate
|> ArraySized.toList
--> [ 1, 20, -30 ]An index that's too high to point to an existing element is ignored and no element is altered
import Linear exposing (Direction(..))
import N exposing (n3)
ArraySized.l3 1 20 30
|> ArraySized.elementAlter ( Up, n3 ) (\x -> x * 10)
|> ArraySized.toList
--> [ 1, 20, 30 ]Flip the order of the elements
ArraySized.l4 "l" "i" "v" "e"
|> ArraySized.reverse
|> ArraySized.toList
--> [ "e", "v", "i", "l" ]Put a new element after all the others
between5And10Elements
|> ArraySized.push "becomes the last"
--: ArraySized String (In (Up6 minX_) (Up11 maxX_))pushMin if you don't know the length maximum
Put a new element after all the others
atLeast5Elements
|> ArraySized.pushMin "becomes the last"
--: ArraySized String (Min (Up6 minX_))push if you know the length maximum
Put an element in the ArraySized at a given index
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n1, n2)
ArraySized.l3 'a' 'c' 'd'
|> ArraySized.insert ( Up, n1 ) 'b'
--: ArraySized Char (In (On N4) (Up4 maxX_))
|> ArraySized.toList
--> [ 'a', 'b', 'c', 'd' ]
ArraySized.l3 'a' 'c' 'd'
|> ArraySized.insert ( Down, n2 ) 'b'
|> ArraySized.toList
--> [ 'a', 'b', 'c', 'd' ]insertMin if you don't know the length maximum
Need the length minimum to not become On
(for results etc.) → |> minTo
Put a new element at an index
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n0, n1)
atLeast5Elements
|> ArraySized.insertMin ( Down, n1 ) "before last"
--: ArraySized String (Min (On N6))
minCons :
element
-> ArraySized element (In (On min) max_)
-> ArraySized element (Min (On (Add1 min)))
minCons =
ArraySized.insertMin ( Up, n0 )insert if you know the length maximum
Need the length minimum to not become On
(for results etc.) → |> minTo
Kick out the element at a given index
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n0)
removeLast between1And10Elements =
between1And10Elements
|> ArraySized.remove ( Down, n0 )Kick out the element at an index
in a given Direction
removeLast =
ArraySized.removeMin ( Down, n0 )This only works when the ArraySized
has at minimum 1 element.
To maybe remove an element,
match on ArraySized.hasAtLeast n1
removeOn) for results, ...?
→ ArraySized.minToTake every filled value, drop every empty
import Emptiable exposing (filled)
ArraySized.l3 ("This" |> filled) Emptiable.empty ("fine" |> filled)
|> ArraySized.fills
--: ArraySized String (In (Up0 minX_) (Up3 maxX_))
|> ArraySized.toList
--> [ "This", "fine" ]map |> fills to get the same functionality as "filterMap"
import Emptiable
ArraySized.l3 "1.2" "2" "hello"
|> ArraySized.map (String.toInt >> Emptiable.fromMaybe)
|> ArraySized.fills
|> ArraySized.toList
--> [ 2 ]If every Emptiable is filled, all of the values.
If any element is empty, empty
import Emptiable exposing (filled)
ArraySized.empty
|> ArraySized.allFill
|> Emptiable.map ArraySized.toList
--> filled []
ArraySized.l3 (filled 1) (filled 2) (filled 3)
|> ArraySized.allFill
|> Emptiable.map ArraySized.toList
--> filled [ 1, 2, 3 ]
ArraySized.l3 (filled 1) Emptiable.empty (filled 3)
|> ArraySized.allFill
--> Emptiable.emptyCan also be used to check whether all/any elements satisfy a given test
import Possibly exposing (Possibly)
import Emptiable exposing (Emptiable)
atMost4 : Int -> Emptiable Int Possibly
atMost4 =
\n ->
if n <= 4 then
n |> Emptiable.filled
else
Emptiable.empty
-- all
ArraySized.l2 2 3
|> ArraySized.map atMost4
|> ArraySized.allFill
|> (/=) Emptiable.empty
--> True
ArraySized.l2 2 7
|> ArraySized.map atMost4
|> ArraySized.allFill
|> (/=) Emptiable.empty
--> False
-- any
ArraySized.l2 -5 300
|> ArraySized.map atMost4
|> ArraySized.allFill
|> (==) Emptiable.empty
--> True
ArraySized.l2 0 0
|> ArraySized.map atMost4
|> ArraySized.allFill
|> (==) Emptiable.empty
--> FalseQ: Why not expose any, all?
A: to push you towards parsing, not validating
Funny aside, allFill can sometimes even be nicer than mapN/andMap
groupCall =
ArraySized.l5 aUser bUser cUser dUser eUser
|> ArraySized.map .phoneNumber
|> ArraySized.allFill
-- vs
groupCall =
map5 ArraySized.l5
aUser.phoneNumber
bUser.phoneNumber
cUser.phoneNumber
dUser.phoneNumber
eUser.phoneNumberA given number of elements in a given direction
import Linear exposing (Direction(..))
import N exposing (n7)
-- its three last elements
ArraySized.upTo n3AtLeast
|> ArraySized.take Down { atLeast = n3 } n3Is the amount taken less than the ArraySized's length minimum?
ArraySized.l8 0 1 2 3 4 5 6 7
|> ArraySized.take Up { atLeast = n7 } n7
--: ArraySized number_ (In (Up7 minX_) (Up7 maxX_))
|> ArraySized.toList
--> [ 0, 1, 2, 3, 4, 5, 6 ]
ArraySized.l8 0 1 2 3 4 5 6 7
|> ArraySized.take Up { atLeast = n7 } n7AtLeast
--: ArraySized number_ (Min (Up7 x_))
ArraySized.l8 0 1 2 3 4 5 6 7
|> ArraySized.minTo
|> ArraySized.take Up { atLeast = n2 } between2And7
--: ArraySized number_ (In (Up2 minX_) (Up7 maxX_))Is the amount taken greater than the ArraySized's length minimum?
ArraySized.upTo between3And6
-- its first four elements
|> ArraySized.take Down { atLeast = n3 } (n4 |> N.minTo n3)Open for alternative API suggestions!
Elements after a certain number of elements
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n2)
ArraySized.l4 0 1 2 3
|> ArraySized.drop Down n2
--: ArraySized number_ (In (Up2 minX_) (Up2 maxX_))
|> ArraySized.toList
--> [ 0, 1 ]
between6And10Elements
|> ArraySized.drop Up between2And3
--: ArraySized number_ (In (Up3 minX_) (Up8 maxX_))dropMinhasAtLeast, then dropElements after a certain number of elements
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n2)
atLeast6Elements
|> ArraySized.dropMin Down n2
--: ArraySized ... (Min (On N4))Split the ArraySized into equal-sized (except remainder) slices
in a given Direction
chunks: the ArraySized divided into equal-sized Arrsremainder: values to one side that don't fill a whole group↓
import Linear exposing (Direction(..))
import N exposing (n0, n5)
ArraySized.l7 1 2 3 4 5 6 7
|> ArraySized.toChunksOf Up n5
--: { chunks :
--: ArraySized
--: (ArraySized
--: number_
--: (In (Up5 chunkMinX_) (Up5 chunkMaxX))
--: )
--: (In (Up0 minX_) (Up7 maxX_))
--: , remainder :
--: ArraySized
--: number_
--: (In
--: (Up0 remainderMinX_)
--: (Up4 chunkMaxX)
--: )
--: }
|> .remainder
|> ArraySized.toList
--> [ 6, 7 ]
ArraySized.l7 1 2 3 4 5 6 7
|> ArraySized.toChunksOf Down n5
|> .remainder
|> ArraySized.toList
--> [ 1, 2 ]Combine each element with an element at the same index from a given ArraySized into a tuple
Every element beyond the minimum length of both is't part of the final ArraySized
import ArraySized
answer
|> ArraySized.and guess
|> ArraySized.map
(\( answerChar, guessChar ) ->
{ directMatch = guessChar == answerChar }
)This is often misused
Glue elements of an ArraySized with an amount of elements in a range
to the end of a given direction
import Linear exposing (Direction(..))
ArraySized.l3 1 2 3
|> ArraySized.attach Up (ArraySized.l3 4 5 6)
--: ArraySized number_ (In (Up6 minX_) (Up6 maxX_))
|> ArraySized.toList
--> [ 1, 2, 3, 4, 5, 6 ]
ArraySized.l3 1 2 3
|> ArraySized.attach Down (ArraySized.l3 4 5 6)
|> ArraySized.toList
--> [ 4, 5, 6, 1, 2, 3 ]Don't know both length maxima? → attachMin
Glue elements of an ArraySized
to the end of a given direction
ArraySized.l3 1 2 3
|> ArraySized.attachMin Up atLeast3Elements
--: ArraySized ... (Min (Up6 x_))
ArraySized.l3 1 2 3
|> ArraySized.attachMin Down atLeast3Elements
--: ArraySized ... (Min (Up6 x_))Know both length maxima? → attach
Pad in a given Direction
with a given ArraySized
to reach a given length
import N exposing (n8)
import Linear exposing (Direction(..))
type Bit
= I
| O
ArraySized.l3 I O I
|> ArraySized.padToLength Down (ArraySized.repeat O) n8
--: ArraySized Bit (In (On N8) (Up8 x_))
|> ArraySized.toList
--> [ O, O, O, O, O, I, O, I ]
ArraySized.l4
(ArraySized.l3 I I I |> ArraySized.maxTo n8)
(ArraySized.l8 O I I I O I O O)
(ArraySized.l8 O I I I O I O O)
(ArraySized.l8 O I I I O I O O)
|> ArraySized.map
(ArraySized.padToLength Down (ArraySized.repeat O) n8)
|> ArraySized.map ArraySized.toList
|> ArraySized.toList
--> [ [ O, O, O, O, O, I, I, I ]
--> , [ O, I, I, I, O, I, O, O ]
--> , [ O, I, I, I, O, I, O, O ]
--> , [ O, I, I, I, O, I, O, O ]
--> ]Place all elements of an ArraySized
between all current members.
Extra elements of either ArraySized are attached to the end
without separating elements from the other ArraySized
import N exposing (n2)
ArraySized.l3 "turtles" "turtles" "turtles"
|> ArraySized.interweave (ArraySized.repeat "on" n2)
--: ArraySized String (In (Up5 minX_) (Up5 maxX_))
|> ArraySized.toList
--> [ "turtles", "on", "turtles", "on", "turtles" ]
ArraySized.l3 "turtles" "turtles" "turtles"
|> ArraySized.interweave (ArraySized.repeat "on" between5And10)
--→ "turtles" "on" "turtles" "on" "turtles" "on" "on" "on" ...
--: ArraySized String (In (Up5 minX_) (Up13 maxX_))Don't know both maxima → interweaveMin
Place all elements of an ArraySized
between all current members.
Extra elements of either ArraySized are attached to the end
without separating elements from the other ArraySized
import N exposing (n2)
ArraySized.l3 "turtles" "turtles" "turtles"
|> ArraySized.interweaveMin
(ArraySized.repeat "on" atLeast2)
--: ArraySized String (Min (Up5 minX_))Know both maxima → interweave
Compared to a range from a lower to an upper bound, is its length in, BelowOrAbove range?
import N exposing (n10, n16)
chooseFormation :
ArraySized Character (In minLength_ N50)
-> Formation
chooseFormation characters =
case characters |> ArraySized.hasIn ( n10, n16 ) of
Ok between10And16 ->
SpecialAttack between10And16
Err (N.Below n9AtMost) ->
Retreat n9AtMost
Err (N.Above n17AtLeast) ->
Fight n17AtLeastCompare its length to a given exact length. Does it match or is it BelowOrAbove?
import N exposing (n7)
chooseFormation :
ArraySized Character (In min N50)
-> Formation
chooseFormation characters =
case characters |> ArraySized.has n7 of
Ok exactly7 ->
SpecialAttack exactly7
Err (N.Below l6AtLeast) ->
Retreat l6AtLeast
Err (N.Above l8AtLeast) ->
Fight l8AtLeastIs its length below (Err) or at least as big as (Ok) a given N?
import N exposing (n5)
atLeast5 :
ArraySized element (In minLength_ max)
-> Maybe (element ArraySized (In (Up5 minX_) max))
atLeast5 =
ArraySized.hasAtLeast n5
>> Result.toMaybeIs its length atMost (Ok) or above (Err) a given length?
-- at least 3 and only up to 50 tags
tag :
ArraySized
String
(In (On (Add3 minFrom3_)) (Up maxTo50_ To N50))
-> (Metadata -> MetadataTagged)
tagIfValidTags :
ArraySized String (In (On (Add3 minFrom3_)) max_)
-> (Metadata -> Maybe MetadataTagged)
tagIfValidTags tags =
case tags |> ArraySized.hasAtMost n50 of
Ok atMost50 ->
tag atMost50 >> Just
Err _ ->
\_ -> NothingChange all elements based on their current values
import N exposing (n25)
aToZ : ArraySized Char (In N26 (N26Plus a_))
aToZ =
ArraySized.upTo n25
|> ArraySized.map inABC
inABC index =
('a' |> Char.toCode)
+ (index |> N.toInt)
|> Char.fromCodeOh look, more type-safety!
Reduce an ArraySized in a given Direction
import Linear exposing (Direction(..))
ArraySized.l4 'l' 'i' 'v' 'e'
|> ArraySized.foldFrom "" Down String.cons
--> "live"
ArraySized.l4 'l' 'i' 'v' 'e'
|> ArraySized.foldFrom "" Up String.cons
--> "evil"
sum =
ArraySized.foldFrom 0 Up (\soFar n -> soFar + n)
product =
ArraySized.foldFrom 0 Up (\soFar n -> soFar * n)A fold in a given Direction
where the initial result is the first element in the ArraySized
import Linear exposing (Direction(..))
ArraySized.l3 234 345 543
|> ArraySized.fold Up Basics.max
--> 543
ArraySized.l3 "go" "to" "uni"
|> ArraySized.fold Down
(\word soFar -> soFar ++ " " ++ word)
--> "uni to go"Fold, starting from one end element transformed to the initial accumulation value,
then reducing what's accumulated in a given Direction
Usually used to convert to a different non-empty structure
import Emptiable exposing (Emptiable)
import N exposing (Add1, In, On)
import Stack exposing (Stacked)
toStackFilled :
ArraySized
element
(In (On (Add1 minFrom1_)) max_)
-> Emptiable (Stacked element) Never
toStackFilled =
ArraySized.foldFromOne Stack.one Stack.onTopLayfold is a simple version that folds directly from the start element:
Stack.fold =
Stack.foldFromOne identityConvert to an Array.
Make these kinds of conversions your final step. Try to keep extra information as long as you can: "wrap early, unwrap late"
import N exposing (n4)
import Array
ArraySized.upTo n4
|> ArraySized.map N.toInt
|> ArraySized.toArray
--> Array.fromList [ 0, 1, 2, 3, 4 ]Convert to a List.
Make these kinds of conversions your final step. Try to keep extra information as long as you can: "wrap early, unwrap late"
import N exposing (n4)
ArraySized.upTo n4
|> ArraySized.map N.toInt
|> ArraySized.toList
--> [ 0, 1, 2, 3, 4 ]Convert to an Emptiable (Stacked ...) never_.
Make these kinds of conversions your final step. Try to keep extra information as long as you can: "wrap early, unwrap late"
import N exposing (n4)
import Emptiable
import Stack
ArraySized.upTo n4
|> ArraySized.map N.toInt
|> ArraySized.toStack
--> Stack.topBelow 0 [ 1, 2, 3, 4 ]
--: Emptiable (Stacked Int) Never
ArraySized.l4 (0 |> Emptiable.filled) Emptiable.empty Emptiable.empty (3 |> Emptiable.filled)
|> ArraySized.fills
|> ArraySized.toStack
--> Stack.topBelow 0 [ 3 ]
--: Emptiable (Stacked Int) PossiblyConvert to a String.
Make these kinds of conversions your final step. Try to keep extra information as long as you can: "wrap early, unwrap late"
import N exposing (n4)
ArraySized.upTo n4
|> ArraySized.map
(\n ->
('a' |> Char.toCode)
+ (n |> N.toInt)
|> Char.fromCode
)
|> ArraySized.toString
--> "abcde"You have a use-case for mapAccumulate/mapAccumulateFrom? → issue/PR
Transform into a Toop.T2 to simplify accessing elements, pattern matching
Transform into a Toop.T3 to simplify accessing elements, pattern matching
Transform into a Toop.T4 to simplify accessing elements, pattern matching
Transform into a Toop.T5 to simplify accessing elements, pattern matching
Transform into a Toop.T6 to simplify accessing elements, pattern matching
Transform into a Toop.T7 to simplify accessing elements, pattern matching
Transform into a Toop.T8 to simplify accessing elements, pattern matching
Transform into a Toop.T9 to simplify accessing elements, pattern matching
Transform into a Toop.T10 to simplify accessing elements, pattern matching
Transform into a Toop.T11 to simplify accessing elements, pattern matching
Transform into a Toop.T12 to simplify accessing elements, pattern matching
Transform into a Toop.T13 to simplify accessing elements, pattern matching
Transform into a Toop.T14 to simplify accessing elements, pattern matching
Transform into a Toop.T15 to simplify accessing elements, pattern matching
Transform into a Toop.T16 to simplify accessing elements, pattern matching
You can generate to<x> with x >= 17 locally,
put them in a module exposing (to<x>) + import as ArraySized
ArraySized with a length
of On range
→ equatable OnValue range
If you have a Min length, you instead only need minToNumber
ArraySized with a length
of equatable OnValue range
→ On range,
allowing it to be altered, compared, ...
If you have a Min length, you instead only need minToOn
ArraySized with a length
with an On minimum
→ equatable OnValue minimum
You'll usually use this to convert to a Min (OnValue ...) length
ArraySized with a length
with an On maximum
→ equatable OnValue maximum
Make an ArraySized with a on maximum length fit into functions with require a higher maximum length
type alias Row =
ArraySized Field (Exactly (On N18))Row's length range can't be added to another length
attach2TemporaryFields : Row -> ...
attach2TemporaryFields rowFromModelOrSomeStorage =
ArraySized.repeat Temporary n2
|> ArraySized.attach Up rowFromModelOrSomeStorageOnly Up<n> x can do that
attach2TemporaryFields :
Row
->
ArraySized
Field
(In (Up20 minX_) (Up20 maxX_))
attach2TemporaryFields rowFromModelOrSomeStorage =
ArraySized.repeat Temporary n2
|> ArraySized.attach Up
(rowFromModelOrSomeStorage
|> ArraySized.minTo n18
|> ArraySized.maxTo n18
)Have a specific minimum in mind? → minTo
Want to increase the upper bound by a on amount? ↓
ArraySized.l4 'a' 'b' 'c' 'd'
--: ArraySized Char (In (Up4 minX_) (Up4 maxX_))
|> ArraySized.minSubtract n2
--: ArraySized Char (In (Up2 minX_) (Up4 maxX_))When is this useful? Very rarely, to preserve type variables
emptiablePush :
Emptiable element possiblyOrNever_
->
(ArraySized
element
(In
(Up minX To minPlusX)
(Up maxX To maxPlusX)
)
->
ArraySized
element
(In (Up minX To minPlusX) (Up maxX To (Add1 maxPlusX)))
)
emptiablePush emptiableElementToPush =
case emptiableElementToPush of
Emptiable.Empty _ ->
ArraySized.maxAdd n1
Emptiable.Filled elementToPush ->
ArraySized.push elementToPush
>> ArraySized.minSubtract n1Here, you could alternatively attach its fromEmptiable.
More in N.minSubtract
Decrease the start and end of its length minimum difference
ArraySized.repeat () n3
--: ArraySized () (In (Up3 (Add2 minX_)) (Up3 maxX_))
|> ArraySized.minEndsSubtract n2
--: ArraySized () (In (Up5 minX_) (Up5 maxX_))N.maxEndsSubtract
has an example of where this can be useful.
Make an ArraySized with a on maximum length fit into functions with require a higher maximum length
type alias Row =
ArraySized Field (Exactly (On N18))Row's length range can't be added to another length
attach2TemporaryFields : Row -> ...
attach2TemporaryFields rowFromModelOrSomeStorage =
ArraySized.repeat Temporary n2
|> ArraySized.attach Up rowFromModelOrSomeStorageOnly Up<n> x can do that
attach2TemporaryFields :
Row
->
ArraySized
Field
(In (Up20 minX_) (Up20 maxX_))
attach2TemporaryFields rowFromModelOrSomeStorage =
ArraySized.repeat Temporary n2
|> ArraySized.attach Up
(rowFromModelOrSomeStorage
|> ArraySized.minTo n18
|> ArraySized.maxTo n18
)Another example: re-enabling an argument's maximum difference
atMost18Elements : ArraySized ... (In min_ (Up maxTo18_ To N18))The argument in atMost18Elements should also fit in atMost19Elements for example
atMost19Elements theArgument -- error
atMost19Elements (theArgument |> ArraySized.maxTo n19)maxAdd n1 is also possible,
but unless you want to preserve the maxTo18_ type variable,
there's no need to not use this absolute operation
Convert the ArraySized (In min ...) to a ArraySized (Min min)
between4And10Elements |> ArraySized.maxToInfinity
--: ArraySized ... (Min (Up4 x_))There is only 1 situation you should use this
To make these the same type
[ atLeast1Element, between1And10Elements ]Elm complains
all the previous elements in the list are
ArraySized ... (Min N1)
[ atLeast1Element
, between1And10Elements |> ArraySized.maxToInfinity
]Have a specific maximum in mind? → maxTo
Want to increase the upper bound by a on amount? ↓
ArraySized.l4 'a' 'b' 'c' 'd'
--: ArraySized Char (In (Up4 minX_) (Up4 maxX_))
|> ArraySized.maxAdd n2
--: ArraySized Char (In (Up4 minX_) (Up6 maxX_))When is this useful? Very rarely, to preserve type variables
emptiablePush :
Emptiable element possiblyOrNever_
->
(ArraySized
element
(In
(Up minX To minPlusX)
(Up maxX To maxPlusX)
)
->
ArraySized
element
(In (Up minX To minPlusX) (Up maxX To (Add1 maxPlusX)))
)
emptiablePush emptiableElementToPush =
case emptiableElementToPush of
Emptiable.Empty _ ->
ArraySized.maxAdd n1
Emptiable.Filled elementToPush ->
ArraySized.push elementToPush
>> ArraySized.minSubtract n1Here, you could alternatively attach its fromEmptiable.
More in N.maxAdd
Decrease the start and end of its length maximum difference
ArraySized.repeat () n3
--: ArraySized () (In (Up3 minX_) (Up3 (Add2 maxX_)))
|> ArraySized.maxEndsSubtract n2
--: ArraySized () (In (Up5 minX_) (Up5 maxX_))N.maxEndsSubtract
has an example of where this can be useful.
allowable-stateTransfer the knowledge about whether 0 is a possible length
toEmptiable :
ArraySized
element
(In (On (N0OrAdd1 possiblyOrNever minFrom1_)) (Up maxTo1_ To N1))
-> Emptiable element possiblyOrNever
toEmptiable =
\arraySized ->
arraySized
|> ArraySized.hasAtLeast1
|> Emptiable.map ArraySized.toOneIt really is just that simple: first try hasAtLeast1,
then map that possibility using the knowledge that the ArraySized
has at least 1 element
toStack :
ArraySized
element
(In (On (N0OrAdd1 possiblyOrNever minFrom1_)) max_)
-> Emptiable (Stacked element) possiblyOrNever
toStack =
\arraySized ->
arraySized
|> ArraySized.hasAtLeast1
|> Emptiable.mapFlat
(ArraySized.foldFromOne Stack.one Down Stack.onTopLay)Change the possiblyOrNever type for the case that its length minimum is 0
never allows you to adapt any variable,
\_ -> yourVariablePossiblyOrNever swaps it for your given variable
fromEmptiable :
Emptiable element possiblyOrNever
->
ArraySized
element
(In (On (N0OrAdd1 possiblyOrNever N0)) (Up1 maxX_))
fromEmptiable =
\emptiable ->
case emptiable of
Emptiable.Filled content ->
ArraySized.one content
-- min = 0 can never happen → any variable possible
|> ArraySized.min0Adapt never
Emptiable.Empty possiblyOrNever ->
ArraySized.empty
|> ArraySized.min0Adapt (\_ -> possiblyOrNever)
-- there's no min successor → any variable possible
|> ArraySized.minAtLeast1Never
-- the other has max = 1. Let's adapt that higher max here
|> ArraySized.maxAdd n1using minAtLeast1Never, maxAdd
Read more at N.min0Adapt
Change the successor type for the case that its length minimum is 1 + ... to allow adapting any variable
fromEmptiable :
Emptiable element possiblyOrNever
->
ArraySized
element
(In (On (N0OrAdd1 possiblyOrNever N0)) (Up1 maxX_))
fromEmptiable =
\emptiable ->
case emptiable of
Emptiable.Filled content ->
ArraySized.one content
-- min = 0 can never happen → any variable possible
|> ArraySized.min0Adapt never
Emptiable.Empty possiblyOrNever ->
ArraySized.empty
|> ArraySized.min0Adapt (\_ -> possiblyOrNever)
-- there's no min successor → any variable possible
|> ArraySized.minAtLeast1Never
-- the other has max = 1. Let's adapt that higher max here
|> ArraySized.maxAdd n1using hasAtLeast1, min0Adapt.
An
Arraythat knows+ about the amount of elements it holdsresult type
Representing a result's numbers as this weird
Up<n> xis what allows the little magic tricks in the library: attaching, taking, dropping, chunking, comparing, ...argument type
to allow the broadest range of desired lengths,
+some variableUpa variable amount to arrive at the desired maximum numberstored type
in your
Modelfor example. They look just like result types but everyUp<n> xbecomesOn N<n>, avoiding type variablesInOn,Exactlyare just shorthands exposed fromN==on bothArraySizeds andNs crashes elm. Compare safely or convertinToNumber