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 error
Is 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.max
The 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
Internal.ArraySized element lengthRange
An Array
that knows about the amount of elements it holds.
-- length >= 5
: ArraySized ... (Min (Up5 x_))
-- 2 <= length <= 12
: ArraySized ... (In (Up2 minX_) (Up12 maxX_))
Representing a result's numbers as this weird Up<n> x
is what allows the little magic tricks in the library:
attaching, taking, dropping, chunking, comparing, ...
-- length = 15
: ArraySized ... (Exactly (On N15))
-- length >= 4
: ArraySized ... (In (On (Add4 minFrom4_)) max_)
-- 4 <= length <= 15
: ArraySized ...
: (In (On (Add4 minFrom4_)) (Up maxTo15_ To N15))
to allow the broadest range of desired lengths,
+
some variableUp
a variable amount
to arrive at the desired maximum numberin your Model
for example.
They look just like result types but every
Up<n> x
becomes On N<n>
,
avoiding type variables
-- length >= 4
: ArraySized ... (Min (On N4))
-- 4 <= length <= 15
: ArraySized ... (In (On N4) (On N15))
-- length = 15
: ArraySized ... (Exactly (On N15))
==
on both ArraySized
s and N
s crashes elm.
Compare safely
or convert inToNumber
repeat : element -> N range -> ArraySized element range
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_))
n1To : N (N.In (N.Up minX N.To minPlusX) max) -> ArraySized (N (N.In (N.Up1 nMinX_) max)) (N.In (N.Up minX N.To minPlusX) max)
Increasing natural numbers from n1
until including a given number
import N exposing (n3, n0)
ArraySized.n1To n3
--: ArraySized
--: (N (In (Up1 nMinX_) (Up3 maxX)))
--: (In (Up3 minX_) (Up3 maxX))
|> ArraySized.map N.toInt
|> ArraySized.toList
--> [ 1, 2, 3 ]
ArraySized.n1To n0
--: ArraySized
--: (N (In (Up1 nMinX_) (Up0 maxX)))
--: (In (Up0 minX_) (Up0 maxX))
|> ArraySized.map N.toInt
|> ArraySized.toList
--> []
-- This does look weird at first glance...
-- The ArraySized says it has Ns in it that are impossible to construct!
-- but I promise it makes sense:
-- The ArraySized is empty, so we're all good after all
ArraySized.n1To between2And9
|> ArraySized.map (N.add n3)
--: ArraySized
--: (N (In (Up5 nMinX_) (Up12 maxX)))
--: (In (Up3 minX_) (Up10 maxX))
To add index info to your ArraySized
, use andIndexes
random : Random.Generator element -> N (N.In min (N.Up maxX N.To (N.Add1 maxFrom1PlusX))) -> Random.Generator (ArraySized element (N.In min (N.Up maxX N.To (N.Add1 maxFrom1PlusX))))
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 well with
Random.andThen
(ArraySized.random <element>)
(N.randomIn ( <length min>, <length max> ))
fuzz : Fuzzer element -> N (N.In min (N.Up maxX N.To (N.Add1 maxFrom1PlusX))) -> Fuzzer (ArraySized element (N.In min (N.Up maxX N.To (N.Add1 maxFrom1PlusX))))
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
inFuzz : Fuzzer element -> ( N (N.In lowerLimitMin (N.Up lowerLimitMaxToUpperLimitMin_ N.To upperLimitMin)), N (N.In (N.On upperLimitMin) upperLimitMax) ) -> Fuzzer (ArraySized element (N.In lowerLimitMin upperLimitMax))
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 ]
--> ]
fromArray : Array element -> ArraySized element (N.Min (N.Up0 x_))
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 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.n1To n6 -- big yes
fromList : List element -> ArraySized element (N.Min (N.Up0 minX_))
Create 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.n1To n6 -- big yes
fromEmptiable : Emptiable element possiblyOrNever -> ArraySized element (N.In (N.On (N0OrAdd1 possiblyOrNever N0)) (N.Up1 maxX_))
On 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
fromStack : Emptiable (Stacked element) possiblyOrNever -> ArraySized element (N.Min (N.On (N0OrAdd1 possiblyOrNever N0)))
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.n1To n6 -- big yes
fromString : String -> ArraySized Char (N.Min (N.Up0 minX_))
Create from the Char
s 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>
empty : ArraySized element_ (N.In (N.Up0 minX_) (N.Up0 maxX_))
No elements
ArraySized.empty
--: ArraySized element_ (In (Up0 minX_) (Up0 maxX_))
|> ArraySized.push ":)"
--: ArraySized String (In (Up1 minX_) (Up1 maxX_))
l2 : element -> element -> ArraySized element (N.In (N.Up2 minX_) (N.Up2 maxX_))
Create with 2 given elements in the order they are supplied
l3 : element -> element -> element -> ArraySized element (N.In (N.Up3 minX_) (N.Up3 maxX_))
Create with 3 given elements in the order they are supplied
l4 : element -> element -> element -> element -> ArraySized element (N.In (N.Up4 minX_) (N.Up4 maxX_))
Create with 4 given elements in the order they are supplied
l5 : element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up5 minX_) (N.Up5 maxX_))
Create with 5 given elements in the order they are supplied
l6 : element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up6 minX_) (N.Up6 maxX_))
Create with 6 given elements in the order they are supplied
l7 : element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up7 minX_) (N.Up7 maxX_))
Create with 7 given elements in the order they are supplied
l8 : element -> element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up8 minX_) (N.Up8 maxX_))
Create with 8 given elements in the order they are supplied
l9 : element -> element -> element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up9 minX_) (N.Up9 maxX_))
Create with 9 given elements in the order they are supplied
l10 : element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up10 minX_) (N.Up10 maxX_))
Create with 10 given elements in the order they are supplied
l11 : element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up11 minX_) (N.Up11 maxX_))
Create with 11 given elements in the order they are supplied
l12 : element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up12 minX_) (N.Up12 maxX_))
Create with 12 given elements in the order they are supplied
l13 : element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up13 minX_) (N.Up13 maxX_))
Create with 13 given elements in the order they are supplied
l14 : element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up14 minX_) (N.Up14 maxX_))
Create with 14 given elements in the order they are supplied
l15 : element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> element -> ArraySized element (N.In (N.Up15 minX_) (N.Up15 maxX_))
Create with 15 given elements in the order they are supplied
length : ArraySized element_ range -> N range
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_))
element : ( Linear.Direction, N (N.In (N.On (N.Add1 indexMin_)) (N.Up indexMaxToMin_ N.To min)) ) -> ArraySized element (N.In (N.On min) max_) -> element
Its element at a valid location
in a given Direction
Remember that indexes are 1-indexed!
import Linear exposing (Direction(..))
import N exposing (n1, n2)
ArraySized.l4 0 1 2 3
|> ArraySized.element ( Up, n1 )
--> 0
ArraySized.l4 0 1 2 3
|> ArraySized.element ( Down, n2 )
--> 2
elementTry : ( Linear.Direction, N indexRange_ ) -> ArraySized element range_ -> Emptiable element Possibly
Its 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 3
hasIn : ( N (N.In lowerLimitMin (N.Up lowerLimitMaxX N.To (N.Add1 lowerLimitMaxPlusXFrom1))), N (N.In (N.Up upperLimitMinX N.To upperLimitMinPlusX) upperLimitMax) ) -> ArraySized element (N.In min max) -> Result (N.BelowOrAbove (ArraySized element (N.In min (N.Up lowerLimitMaxX N.To lowerLimitMaxPlusXFrom1))) (ArraySized element (N.In (N.Up upperLimitMinX N.To (N.Add1 upperLimitMinPlusX)) max))) (ArraySized element (N.In lowerLimitMin upperLimitMax))
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 n17AtLeast
has : N (N.In (N.Up minX N.To comparedAgainstMinPlusX) (N.Up maxX N.To (N.Add1 comparedAgainstMaxPlusXFrom1))) -> ArraySized element (N.In min max) -> Result (N.BelowOrAbove (ArraySized element (N.In min (N.Up maxX N.To comparedAgainstMaxPlusXFrom1))) (ArraySized element (N.In (N.Up minX N.To (N.Add1 comparedAgainstMinPlusX)) max))) (ArraySized element (N.In (N.Up minX N.To comparedAgainstMinPlusX) (N.Up maxX N.To (N.Add1 comparedAgainstMaxPlusXFrom1))))
Compare 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 l8AtLeast
hasAtLeast : N (N.In lowerLimitMin (N.Up lowerLimitMaxX N.To (N.Add1 lowerLimitMaxFrom1PlusX))) -> ArraySized element (N.In min max) -> Result (ArraySized element (N.In min (N.Up lowerLimitMaxX N.To lowerLimitMaxFrom1PlusX))) (ArraySized element (N.In lowerLimitMin max))
Is 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.toMaybe
hasAtMost : N (N.In (N.Up upperLimitMinX N.To upperLimitMinPlusX) upperLimitMax) -> ArraySized element (N.In min max) -> Result (ArraySized element (N.In (N.Up upperLimitMinX N.To (N.Add1 upperLimitMinPlusX)) max)) (ArraySized element (N.In min upperLimitMax))
Is 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 _ ->
\_ -> Nothing
elementReplace : ( Linear.Direction, N indexRange_ ) -> (() -> element) -> ArraySized element range -> ArraySized element range
Set the element at an index
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n2, n3)
ArraySized.l3 "I" "am" "ok"
|> ArraySized.elementReplace ( Up, n3 )
(\() -> "confusion")
|> ArraySized.toList
--> [ "I", "am", "confusion" ]
ArraySized.l3 "I" "am" "ok"
|> ArraySized.elementReplace ( Down, n2 )
(\() -> "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 (n4)
ArraySized.l3 "I" "am" "ok"
|> ArraySized.elementReplace ( Down, n4 )
(\() -> "feel")
|> ArraySized.toList
--> [ "I", "am", "ok" ]
elementAlter : ( Linear.Direction, N indexRange_ ) -> (element -> element) -> ArraySized element range -> ArraySized element range
Change the element at an index
in a given Direction
based on its previous value
import Linear exposing (Direction(..))
import N exposing (n1)
ArraySized.l3 1 20 30
|> ArraySized.elementAlter ( Up, n1 ) (\x -> x * 10)
|> ArraySized.toList
--> [ 10, 20, 30 ]
ArraySized.l3 1 20 30
|> ArraySized.elementAlter ( Down, n1 ) negate
|> ArraySized.toList
--> [ 1, 20, -30 ]
An index that's 0 or too high to point to an existing element is ignored and no element is altered
import Linear exposing (Direction(..))
import N exposing (n0, n4)
ArraySized.l3 1 20 30
|> ArraySized.elementAlter ( Up, n0 ) (\x -> x * 10)
|> ArraySized.elementAlter ( Up, n4 ) (\x -> x * 10)
|> ArraySized.toList
--> [ 1, 20, 30 ]
reverse : ArraySized element range -> ArraySized element range
Flip the order of the elements
ArraySized.l4 "l" "i" "v" "e"
|> ArraySized.reverse
|> ArraySized.toList
--> [ "e", "v", "i", "l" ]
andIndexes : ArraySized element (N.In (N.Up minX N.To minPlusX) max) -> ArraySized { element : element, index : N (N.In (N.Up1 nMinX_) max) } (N.In (N.Up minX N.To minPlusX) max)
Add index info to each element.
import N exposing (n1, n2, n3)
ArraySized.l3 'a' 'b' 'c'
|> ArraySized.andIndexes
|> ArraySized.toList
--→ [ { element = 'a', index = n1 |> N.maxTo n3 }
--→ , { element = 'b', index = n2 |> N.minTo n1 |> N.maxTo n3 }
--→ , { element = 'b', index = n3 |> N.minTo n1 }
--→ ]
map : (element -> mappedElement) -> ArraySized element range -> ArraySized mappedElement range
Change all elements based on their current values
import N exposing (n25)
aToZ : ArraySized Char (In N26 (N26Plus a_))
aToZ =
ArraySized.n1To n25
|> ArraySized.map inABC
inABC index =
('a' |> Char.toCode)
+ (index |> N.toInt)
|> Char.fromCode
Oh look, more type-safety!
mapFoldFrom : folded -> Linear.Direction -> ({ element : element, folded : folded } -> { element : mappedElement, folded : folded }) -> ArraySized element range -> { mapped : ArraySized mappedElement range, folded : folded }
Map each element using information collected from previous steps,
folding in a given Direction
from given initial information.
Both the mapped ArraySized
and the folded information will be returned
You'll often find this under the name "mapAccum"
import Linear exposing (Direction(..))
ArraySized.l3 1 2 3
|> ArraySized.mapFoldFrom 0
Down
(\state ->
{ element = state.folded
, folded = state.folded + state.element
}
)
--→ { mapped = ArraySized.l3 5 3 0, folded = 6 }
mapIndexed : Direction -> (Int -> a -> b) -> (ArraySized a l -> ArraySized b l)
mapIndexed indexDirection mapAtIndex =
ArraySized.mapFoldFrom 0
indexDirection
(\state ->
{ element = state.element |> mapAtIndex state.folded
, folded = state.folded + 1
}
)
>> .mapped
ArraySized.l4 'h' 'i' 'y' 'o'
|> mapIndexed Up Tuple.pair
--→ ArraySized.l4 ( 0, 'h' ) ( 1, 'i' ) ( 2, 'y' ) ( 3, 'o' )
ArraySized.l4 'h' 'i' 'y' 'o'
|> mapIndexed Down Tuple.pair
--→ ArraySized.l4 ( 3, 'h' ) ( 2, 'i' ) ( 1, 'y' ) ( 0, 'o' )
push : element -> ArraySized element (N.In (N.Up minX N.To minPlusX) (N.Up maxX N.To maxPlusX)) -> ArraySized element (N.In (N.Up minX N.To (N.Add1 minPlusX)) (N.Up maxX N.To (N.Add1 maxPlusX)))
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
pushMin : element -> ArraySized element (N.In (N.Up minX N.To minPlusX) max_) -> ArraySized element (N.Min (N.Up minX N.To (N.Add1 minPlusX)))
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
insert : ( Linear.Direction, N (N.In (N.On (N.Add1 indexMinFrom1_)) (N.Up indexMaxToMin_ N.To (N.Add1 min))) ) -> element -> ArraySized element (N.In (N.On min) (N.Up maxX N.To maxPlusX)) -> ArraySized element (N.In (N.On (N.Add1 min)) (N.Up maxX N.To (N.Add1 maxPlusX)))
Put an element in the ArraySized
at a given index
in a given Direction
Remember that indexes are 1-indexed!
import Linear exposing (Direction(..))
import N exposing (n2, n3)
ArraySized.l3 'a' 'c' 'd'
|> ArraySized.insert ( Up, n2 ) 'b'
--: ArraySized Char (In (On N4) (Up4 maxX_))
|> ArraySized.toList
--> [ 'a', 'b', 'c', 'd' ]
ArraySized.l3 'a' 'c' 'd'
|> ArraySized.insert ( Down, n3 ) '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
insertMin : ( Linear.Direction, N (N.In (N.On (N.Add1 indexMinFrom1_)) (N.Up indexMaxToMin_ N.To (N.Add1 min))) ) -> element -> ArraySized element (N.In (N.On min) max_) -> ArraySized element (N.Min (N.On (N.Add1 min)))
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
remove : ( Linear.Direction, N (N.In (N.On (N.Add1 indexMinFrom1_)) (N.Up indexMaxToMinFrom1_ N.To (N.Add1 minFrom1))) ) -> ArraySized element (N.In (N.On (N.Add1 minFrom1)) (N.Up maxX N.To (N.Add1 maxFrom1PlusX))) -> ArraySized element (N.In (N.On minFrom1) (N.Up maxX N.To maxFrom1PlusX))
Kick out the element at a given index
in a given Direction
Remember that indexes are 1-indexed!
import Linear exposing (Direction(..))
import N exposing (n1)
removeLast between1And10Elements =
between1And10Elements
|> ArraySized.remove ( Down, n1 )
removeMin
removeMin
removeMin : ( Linear.Direction, N (N.In (N.On (N.Add1 indexMinFrom1_)) indexMax_) ) -> ArraySized element (N.In (N.On (N.Add1 minFrom1)) max) -> ArraySized element (N.In (N.On minFrom1) max)
Kick out the element at an index
in a given Direction
Remember that indexes are 1-indexed!
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
remove
On
) for results, ...?
→ ArraySized.minTo
fills : ArraySized (Emptiable fill possiblyOrNever_) (N.In min_ max) -> ArraySized fill (N.In (N.Up0 minX_) max)
Take 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" ]
Use 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 ]
allFill : ArraySized (Emptiable fill possiblyOrNever) range -> Emptiable (ArraySized fill range) possiblyOrNever
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.empty
Can 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
--> False
Q: 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.phoneNumber
allOk : ArraySized (Result error ok) range -> Result (Emptiable (Stacked error) Basics.Never) (ArraySized ok range)
If every Result
is Ok
, all of the values.
If any element is Err
, all the errors.
import Stack
ArraySized.empty
|> ArraySized.allOk
|> Result.map ArraySized.toList
--> Ok []
ArraySized.l3 (Ok 1) (Ok 2) (Ok 3)
|> ArraySized.allOk
|> Result.map ArraySized.toList
--> Ok [ 1, 2, 3 ]
ArraySized.l3 (Ok 1) (Err "not a number") (Ok 3)
|> ArraySized.allOk
--> Err (Stack.one "not a number")
take : Linear.Direction -> { atLeast : N (N.In takenMin (N.Up takenMaxToMin_ N.To min)) } -> N (N.In takenMin takenMax) -> ArraySized element (N.In (N.On min) max_) -> ArraySized element (N.In takenMin takenMax)
A given number of elements in a given direction
import Linear exposing (Direction(..))
import N exposing (n7)
-- its three last elements
ArraySized.n1To n3AtLeast
|> ArraySized.take Down { atLeast = n3 } n3
Is 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.n1To between3And6
-- its first four elements
|> ArraySized.take Down { atLeast = n3 } (n4 |> N.minTo n3)
If you're having trouble understanding the atLeast
field, think of looking
at the implementation of take
will help:
take direction { atLeast } toTakeAmount =
minTo atLeast
>> takeCurrentMin direction toTakeAmount
Open for alternative API suggestions! I'm actually close to removing
take
in favor of takeCurrentMin
and renaming that to take
. Let me know what you think!
takeCurrentMin : Linear.Direction -> N (N.In min takenMax) -> ArraySized element (N.In min max_) -> ArraySized element (N.In min takenMax)
Take a given number of elements in a given direction
As the simpler version of take
you can only take at least the type's minimum amount.
It's most of the time not what you want, since you usually want a shorter array minimum after taking.
drop : Linear.Direction -> N (N.In (N.Down maxPlusX N.To takenMaxPlusX) (N.Down min N.To takenMin)) -> ArraySized element (N.In (N.On min) (N.Up maxX N.To maxPlusX)) -> ArraySized element (N.In (N.On takenMin) (N.Up maxX N.To takenMaxPlusX))
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_))
dropMin
dropMax
dropMin : Linear.Direction -> N (N.In droppedMin_ (N.Down min N.To takenMin)) -> ArraySized element (N.In (N.On min) max) -> ArraySized element (N.In (N.On takenMin) max)
Elements 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))
drop
dropMax
dropMax : Linear.Direction -> N (N.In (N.Down max N.To differenceMax) toDropMax_) -> ArraySized element (N.In min_ (N.On max)) -> ArraySized element (N.In (N.Up0 minX_) (N.On differenceMax))
Elements after a certain number of elements
in a given Direction
import Linear exposing (Direction(..))
import N exposing (n2, n5)
ArraySized.l4 0 1 2 3
|> ArraySized.dropMax Down (3 |> N.intToIn ( n2, n5 ))
--: ArraySized number_ (In (Up0 minX_) (On N2))
|> ArraySized.toList
--> [ 0 ]
drop
dropMin
toSize : Linear.Direction -> N (N.In (N.Up newMinX N.To newMinPlusX) newMax) -> (N (N.In (N.Up1 indexMin_) newMax) -> element) -> ArraySized element range_ -> ArraySized element (N.In (N.Up newMinX N.To newMinPlusX) newMax)
Reach a given length:
If the current length is greater than a given length, take
the new length in a given direction
If the current length is less than a given length, pad further in a given Direction
based on the index in the final ArraySized
.
import N exposing (n8)
import Linear exposing (Direction(..))
type Bit
= I
| O
ArraySized.l3 I O I
|> ArraySized.toSize Down n8 (\_ -> O)
--: 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.toSize Down n8 (\_ -> O))
|> 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 ]
--> ]
toChunksOf : Linear.Direction -> N (N.In (N.On (N.Add1 chunkMinFrom1)) (N.Up chunkMaxX N.To (N.Add1 chunkMaxFrom1PlusX))) -> ArraySized element (N.In minLength_ max) -> { chunks : ArraySized (ArraySized element (N.In (N.On (N.Add1 chunkMinFrom1)) (N.Up chunkMaxX N.To (N.Add1 chunkMaxFrom1PlusX)))) (N.In (N.Up0 minX_) max), remainder : ArraySized element (N.In (N.Up remainderMinX N.To remainderMinX) (N.Up chunkMaxX N.To chunkMaxFrom1PlusX)) }
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 ]
and : ArraySized nextElement range -> ArraySized element range -> ArraySized ( element, nextElement ) range
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
attach : Linear.Direction -> ArraySized element (N.In (N.Up minPlusX N.To minSumPlusX) (N.Up maxPlusX N.To maxSumPlusX)) -> ArraySized element (N.In (N.Up minX N.To minPlusX) (N.Up maxX N.To maxPlusX)) -> ArraySized element (N.In (N.Up minX N.To minSumPlusX) (N.Up maxX N.To maxSumPlusX))
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
attachMin : Linear.Direction -> ArraySized element (N.In (N.Up minPlusX N.To minSumPlusX) extensionMax_) -> ArraySized element (N.In (N.Up x N.To minPlusX) max_) -> ArraySized element (N.Min (N.Up x N.To minSumPlusX))
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
interweave : ArraySized element (N.In (N.Up minPlusX N.To minSumPlusX) (N.Up maxPlusX N.To maxSumPlusX)) -> ArraySized element (N.In (N.Up x N.To minPlusX) (N.Up x N.To maxPlusX)) -> ArraySized element (N.In (N.Up x N.To minSumPlusX) (N.Up x N.To maxSumPlusX))
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
interweaveMin : ArraySized element (N.In (N.Up minPlusX N.To minSumPlusX) interweaveMax_) -> ArraySized element (N.In (N.Up x N.To minPlusX) max_) -> ArraySized element (N.Min (N.Up x N.To minSumPlusX))
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
foldFrom : result -> Linear.Direction -> (element -> result -> result) -> ArraySized element range_ -> result
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)
fold : Linear.Direction -> (element -> element -> element) -> ArraySized element (N.In (N.On (N.Add1 minFrom1_)) max_) -> element
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"
foldFromOne : (element -> folded) -> Linear.Direction -> (element -> folded -> folded) -> ArraySized element (N.In (N.On (N.Add1 minFrom1_)) max_) -> folded
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.onTopLay
fold
is a simple version that folds directly from the start element:
Stack.fold =
Stack.foldFromOne identity
toArray : ArraySized element range_ -> Array element
Convert 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.n1To n4
|> ArraySized.map N.toInt
|> ArraySized.toArray
--> Array.fromList [ 1, 2, 3, 4 ]
toList : ArraySized element range_ -> List element
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.n1To n4
|> ArraySized.map N.toInt
|> ArraySized.toList
--> [ 1, 2, 3, 4 ]
toEmptiable : ArraySized element (N.In (N.On (N0OrAdd1 possiblyOrNever minFrom1_)) (N.Up maxTo1_ N.To N1)) -> Emptiable element possiblyOrNever
On empty
Emptiable.empty
,
on one
filled
with its only value
Emptiness type information is transferred
toStack : ArraySized element (N.In (N.On (N0OrAdd1 possiblyOrNever minFrom1_)) max_) -> Emptiable (Stacked element) possiblyOrNever
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.n1To n4
|> ArraySized.map N.toInt
|> ArraySized.toStack
--> Stack.topBelow 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) Possibly
to2 : ArraySized element (N.In (N.On (N.Add2 minFrom2_)) (N.Up maxTo2_ N.To N2)) -> Toop.T2 element element
Transform into a Toop.T2
to simplify accessing elements, pattern matching
to3 : ArraySized element (N.In (N.On (N.Add3 minFrom3_)) (N.Up maxTo3_ N.To N3)) -> Toop.T3 element element element
Transform into a Toop.T3
to simplify accessing elements, pattern matching
to4 : ArraySized element (N.In (N.On (N.Add4 minFrom4_)) (N.Up maxTo4_ N.To N4)) -> Toop.T4 element element element element
Transform into a Toop.T4
to simplify accessing elements, pattern matching
to5 : ArraySized element (N.In (N.On (N.Add5 minFrom5_)) (N.Up maxTo5_ N.To N5)) -> Toop.T5 element element element element element
Transform into a Toop.T5
to simplify accessing elements, pattern matching
to6 : ArraySized element (N.In (N.On (N.Add6 minFrom6_)) (N.Up maxTo6_ N.To N6)) -> Toop.T6 element element element element element element
Transform into a Toop.T6
to simplify accessing elements, pattern matching
to7 : ArraySized element (N.In (N.On (N.Add7 minFrom7_)) (N.Up maxTo7_ N.To N7)) -> Toop.T7 element element element element element element element
Transform into a Toop.T7
to simplify accessing elements, pattern matching
to8 : ArraySized element (N.In (N.On (N.Add8 minFrom8_)) (N.Up maxTo8_ N.To N8)) -> Toop.T8 element element element element element element element element
Transform into a Toop.T8
to simplify accessing elements, pattern matching
to9 : ArraySized element (N.In (N.On (N.Add9 minFrom9_)) (N.Up maxTo9_ N.To N9)) -> Toop.T9 element element element element element element element element element
Transform into a Toop.T9
to simplify accessing elements, pattern matching
to10 : ArraySized element (N.In (N.On (N.Add10 minFrom10_)) (N.Up maxTo10_ N.To N10)) -> Toop.T10 element element element element element element element element element element
Transform into a Toop.T10
to simplify accessing elements, pattern matching
to11 : ArraySized element (N.In (N.On (N.Add11 minFrom11_)) (N.Up maxTo11_ N.To N11)) -> Toop.T11 element element element element element element element element element element element
Transform into a Toop.T11
to simplify accessing elements, pattern matching
to12 : ArraySized element (N.In (N.On (N.Add12 minFrom2_)) (N.Up maxTo12_ N.To N12)) -> Toop.T12 element element element element element element element element element element element element
Transform into a Toop.T12
to simplify accessing elements, pattern matching
to13 : ArraySized element (N.In (N.On (N.Add13 minFrom13_)) (N.Up maxTo13_ N.To N13)) -> Toop.T13 element element element element element element element element element element element element element
Transform into a Toop.T13
to simplify accessing elements, pattern matching
to14 : ArraySized element (N.In (N.On (N.Add14 minFrom14_)) (N.Up maxTo14_ N.To N14)) -> Toop.T14 element element element element element element element element element element element element element element
Transform into a Toop.T14
to simplify accessing elements, pattern matching
to15 : ArraySized element (N.In (N.On (N.Add15 minFrom15_)) (N.Up maxTo15_ N.To N15)) -> Toop.T15 element element element element element element element element element element element element element element element
Transform into a Toop.T15
to simplify accessing elements, pattern matching
inToNumber : ArraySized element (N.In (N.On min) (N.On max)) -> ArraySized element (N.In min max)
ArraySized
with a length
of On
range
→ equatable OnValue
range
If you have a Min
length, you instead only need minToNumber
inToOn : ArraySized element (N.In min max) -> ArraySized element (N.In (N.On min) (N.On max))
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
minToNumber : ArraySized element (N.In (N.On min) max) -> ArraySized element (N.In min max)
ArraySized
with a length
with an On
minimum
→ equatable OnValue
minimum
You'll usually use this to convert to a Min (OnValue ...)
length
minToOn : ArraySized element (N.In min max) -> ArraySized element (N.In (N.On min) max)
ArraySized
with a length
with an equatable OnValue
minimum
→ On
minimum,
allowing it to be altered, compared, ...
You'll usually use this to convert to a Min (On ...)
length
maxToNumber : ArraySized element (N.In min (N.On max)) -> ArraySized element (N.In min max)
ArraySized
with a length
with an On
maximum
→ equatable OnValue
maximum
maxToOn : ArraySized element (N.In min max) -> ArraySized element (N.In min (N.On max))
ArraySized
with a length
with an equatable OnValue
maximum
→ On
maximum,
allowing it to be altered, compared, ...
minTo : N (N.In minNew (N.Up minNewMaxToMin_ N.To min)) -> ArraySized element (N.In (N.On min) max) -> ArraySized element (N.In minNew max)
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 rowFromModelOrSomeStorage
Only 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
)
minTo0 : ArraySized element (N.In min_ max) -> ArraySized element (N.In (N.Up0 minX_) max)
Equivalent to minTo n0
,
except that the current length minimum isn't required to be On
.
It can be used to make argument types look nicer.
See also N.minTo0
minSubtract : N (N.In maxDecreaseMin_ (N.Down minPlusX N.To minDecreasedPlusX)) -> ArraySized element (N.In (N.Up x N.To minPlusX) max) -> ArraySized element (N.In (N.Up x N.To minDecreasedPlusX) max)
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 n1
Here, you could alternatively attach
its fromEmptiable
.
More in N.minSubtract
minEndsSubtract : N (N.In (N.Down minX N.To minXDecreased) (N.Down minPlusX N.To minPlusXDecreased)) -> ArraySized element (N.In (N.Up minX N.To minPlusX) max) -> ArraySized element (N.In (N.Up minXDecreased N.To minPlusXDecreased) max)
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.
maxTo : N (N.In (N.On maxNewMin) maxNew) -> ArraySized element (N.In min (N.Up maxToMaxNewMin_ N.To maxNewMin)) -> ArraySized element (N.In min maxNew)
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 rowFromModelOrSomeStorage
Only 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
maxToInfinity : ArraySized element (N.In min max_) -> ArraySized element (N.Min min)
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
]
maxAdd : N (N.In maxIncreaseMin_ (N.Up maxPlusX N.To maxIncreasedPlusX)) -> ArraySized element (N.In min (N.Up x N.To maxPlusX)) -> ArraySized element (N.In min (N.Up x N.To maxIncreasedPlusX))
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 n1
Here, you could alternatively attach
its fromEmptiable
.
More in N.maxAdd
maxEndsSubtract : N (N.In (N.Down maxPlusX N.To maxPlusXDecreased) (N.Down maxX N.To maxXDecreased)) -> ArraySized element (N.In min (N.Up maxX N.To maxPlusX)) -> ArraySized element (N.In min (N.Up maxXDecreased N.To maxPlusXDecreased))
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-state
hasAtLeast1 : ArraySized element (N.In (N.On (N0OrAdd1 possiblyOrNever minFrom1_)) max) -> Emptiable (ArraySized element (N.In (N.Up1 minX_) max)) possiblyOrNever
Transfer 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.toOne
It 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)
min0Adapt : (possiblyOrNever -> adaptedPossiblyOrNever) -> ArraySized element (N.In (N.On (N0OrAdd1 possiblyOrNever minFrom1)) max) -> ArraySized element (N.In (N.On (N0OrAdd1 adaptedPossiblyOrNever minFrom1)) max)
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 n1
using minAtLeast1Never
, maxAdd
Read more at N.min0Adapt
minAtLeast1Never : ArraySized element (N.In (N.On (N0OrAdd1 possiblyOrNever Basics.Never)) max) -> ArraySized element (N.In (N.On (N0OrAdd1 possiblyOrNever minFrom1_)) max)
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 n1
using hasAtLeast1
, min0Adapt
.