Natural number within a typed range
A bounded natural number >= 0
-- ≥ 4
N (Min (Up4 x_))
-- 2 ≤ n ≤ 12
N (In (Up2 minX_) (Up12 maxX_))
-- n3 :
N (In (Up3 minX_) (Up3 maxX_))
The type variable enables adding, subtracting.
Consider the "Up
" thing an implementation detail
n3
|> N.add n6
--: N (In (Up9 minX_) (Up9 maxX_))
|> N.multiplyBy n5
--: N (Min (Up9 minX_))
|> N.remainderBy n4
--: N (In (Up0 minX_) (Up3 maxX_))
|> N.inToNumber
--: N (In N0 N3)
--> n1 |> N.minTo n0 |> N.maxTo n3 |> N.inToNumber
-- ≥ 0, any limitations allowed
N range_
-- ≥ 4
N (In (On (Add4 minFrom4_)) max_)
-- 4 ≤ n ≤ 15
N (In (On (Add4 minFrom4_)) (Up maxTo15_ To N15))
In (On (Add4 minFrom4_)) (Up maxTo15_ To N15)
says:
+
some variable = 4+0
|4+1
|4+2
|...
which means it's ≥ 4+
some variable = 15
which means it's ≤ 15what to put in declared types like Model
-- ≥ 4
N (Min (On N4))
-- 2 ≤ n ≤ 12
N (In (On N2) (On N12))
There's also versions of this that don't contain functions internally:
-- ≥ 4
N (Min N4)
-- 2 ≤ n ≤ 12
N (In N2 N12)
somewhere within a minimum & maximum
↓ minimum ↓ maximum
⨯ [✓ ✓ ✓ ✓ ✓ ✓ ✓] ⨯ ⨯ ⨯...
-- 3 ≤ n ≤ 5
N (In (On (Add3 minFrom3_)) (Up maxTo5_ To N5))
-- 0 ≤ n ≤ 100
percent : N (In min_ (Up maxTo100_ To N100)) -> Percent
For every constructable value, the minimum is smaller than the maximum
(that's why In
is opaque)
If you want a number where you just care about the minimum, leave max
as a type variable
↓ minimum ↓ maximum or →
⨯ [✓ ✓ ✓ ✓ ✓ ✓ ✓...
-- any natural number
N (In min_ max_)
A number, at least 5:
N (In (On (Add5 minFrom_)) max_)
→ max_
could be a specific maximum or no maximum at all
n3 : N (In (Up3 minX_) (Up3 maxX_))
between3And6 : N (In (Up3 minX_) (Up6 maxX_))
between3And6 |> N.add n3
--: N (In (Up6 minX_) (Up9 maxX_))
An example where this is useful using typesafe-array:
type Tree branchingFactor element
= Tree
element
(ArraySized
branchingFactor
(Maybe (Tree branchingFactor element))
)
type alias TreeBinaryFull element =
Tree (Exactly (On N2)) element
Remember: ↑ and other ... (
On
...)
are result/stored types, not argument types
Do not use ==
on 2 values storing a range.
It will lead to elm crashing because differences are stored as functions.
Instead,
==
In lowestPossibleAsDifference Infinity
Only stored / result types should use Min
↓ minimum ↓ or →
⨯ [✓ ✓ ✓ ✓ ✓ ✓ ✓...
Sometimes, you simply cannot compute a maximum
intToAbsolute : Int -> N (In (Up0 x_) ??)
↓
intToAbsolute : Int -> N (Min (Up0 x_))
-- n ≥ 5
atLeast5 : N (Min (Up5 x_))
atLeast5 |> N.addMin n3
--: N (Min (Up8 x_))
n3 |> N.addMin atLeast5
--: N (Min (Up8 x_))
Every Min min
is of type In min ...
,
so using a type variable for the maximum on arguments is highly encouraged
when no maximum constraint should be enforced
-- any natural number
N (In min_ max_)
-- number, at least 5
N (In (On (Add5 minFrom5_)) max_)
An example where this is useful using typesafe-array:
type Tree branchingFactor element
= Tree
element
(ArraySized
branchingFactor
(Maybe (Tree branchingFactor element))
)
type alias TreeMulti element =
Tree (Min (On N1)) element
Remember: ↑ and other ... (
On
...)
are result/stored types, not argument types
You can just use Min
(
On
...)
when you don't have disadvantages storing functions.
"The limit is unknown".
Used in the definition of Min
type alias Min min =
In minimum Infinity
In representation representation
Allow only a specific given represented number
result type:
Exactly (On N3)
Use Exactly ...
without On
for storing in a type without internal functions
Exactly N3
This is pretty useless in combination with N
-- argument type
numberToInt : N (Exactly n) -> n -> Int
numberToInt wellThisWasPointless _ =
wellThisWasPointless |> N.toInt
It is useful as a stored & argument type
in combination with typesafe-array
,
byte : ArraySized (Exactly (On N8)) Bit -> Byte
→ A given ArraySized
must have exactly 8 Bit
s
type alias TicTacToeBoard =
ArraySized
(Exactly (On N3))
(ArraySized (Exactly (On N3)) TicTacToeField)
→ A given ArraySized
must have exactly 3 by 3 TicTacToeField
s
Up N0 To asNumber
The fixed difference from 0
to a given number n
You'll find this either to require a certain minimum
entryOnlyForKids : N (In (On (Add6 minFrom6_)) (Up maxTo14_ To N14)) -> ()
entryOnlyForKids _ =
()
Or in a stored type, which looks like a result type
where every Up<n> x
is instead On N<n>
Do not use ==
on 2 numbers in a On
range.
It will lead to elm crashing because differences are stored as functions internally.
Instead, compare in your code or convert to a value for other code:
Not storing functions etc. in app state, events, ... enables
==
, for example==
call → crashCalling ==
on a value will yield the correct result instead of crashing
On
is defined as a difference from 0, so this independent type needed to be created
You can just use On
when you don't have disadvantages storing functions
Up low To high
: a specific number represented as the difference high - low
Just a word in a difference type:
Up low To high
Down high To low
→ distance high - low
Up low toTag high
Down high To low
: a specific number represented as the difference high - low
inRandom : ( N (In minMin (Up minMaxToMaxMin_ To maxMin)), N (In (On maxMin) maxMax) ) -> Random.Generator (N (In minMin maxMax))
Generate a random N
in a range
N.inRandom ( n1, n10 )
--: Random.Generator
--: (N (In (Up1 minX_) (Up10 maxX_)))
inFuzz : ( N (In minMin (Up minMaxToMaxMin_ To maxMin)), N (In (On maxMin) maxMax) ) -> Fuzzer (N (In minMin maxMax))
Fuzzer
for an N
in a given range.
For larger ranges, smaller N
s are preferred
import Fuzz
N.inFuzz ( n3, n6 )
|> Fuzz.map N.toInt
|> Fuzz.examples 10
--> [ 5, 6, 3, 3, 4, 6, 3, 6, 3, 5 ]
If the package exposed every number 0 → 1000+, tools can become unusably slow
So only 0 → 16 are exposed, while larger numbers have to be generated locally
Current method: generate them
into a module N.Local exposing (n<n>, N<n>, Add<n>, Up<n>, ...)
+
import N.Local as N exposing (n<n>, N<n>, Add<n>, Up<n>, ...)
In the future, elm-generate
will allow auto-generating via elm-review
type n
⏭ skip to last
N0OrAdd1 Possibly Basics.Never
The natural number 0
N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never)
The natural number 1
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never))
The natural number 2
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never)))
The natural number 3
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never))))
The natural number 4
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never)))))
The natural number 5
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never))))))
The natural number 6
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never)))))))
The natural number 7
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never))))))))
The natural number 8
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never)))))))))
The natural number 9
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never))))))))))
The natural number 10
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never)))))))))))
The natural number 11
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never))))))))))))
The natural number 12
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never)))))))))))))
The natural number 13
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never))))))))))))))
The natural number 14
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Possibly Basics.Never)))))))))))))))
The natural number 15
N0OrAdd1 Basics.Never n
The natural number 1 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n)
The natural number 2 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n))
The natural number 3 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n)))
The natural number 4 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n))))
The natural number 5 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n)))))
The natural number 6 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n))))))
The natural number 7 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n)))))))
The natural number 8 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n))))))))
The natural number 9 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n)))))))))
The natural number 10 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n))))))))))
The natural number 11 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n)))))))))))
The natural number 12 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n))))))))))))
The natural number 13 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n)))))))))))))
The natural number 14 +
a given n
N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never n))))))))))))))
The natural number 15 +
a given n
Up x To x
0
as the difference Up x To x
Up x To (N0OrAdd1 Basics.Never x)
1
as the difference Up x To (N0OrAdd1 Possibly x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x))
2
as the difference Up x To (Add2 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x)))
3
as the difference Up x To (Add3 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x))))
4
as the difference Up x To (Add4 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x)))))
5
as the difference Up x To (Add5 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x))))))
6
as the difference Up x To (Add6 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x)))))))
7
as the difference Up x To (Add7 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x))))))))
8
as the difference Up x To (Add8 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x)))))))))
9
as the difference Up x To (Add9 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x))))))))))
10
as the difference Up x To (Add10 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x)))))))))))
11
as the difference Up x To (Add11 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x))))))))))))
12
as the difference Up x To (Add12 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x)))))))))))))
13
as the difference Up x To (Add13 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x))))))))))))))
14
as the difference Up x To (Add14 x)
Up x To (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never (N0OrAdd1 Basics.Never x)))))))))))))))
15
as the difference Up x To (Add15 x)
n0 : N (In (Up0 minX_) (Up0 maxX_))
The specific natural number 0
n1 : N (In (Up1 minX_) (Up1 maxX_))
The specific natural number 1
n2 : N (In (Up2 minX_) (Up2 maxX_))
The N
2
n3 : N (In (Up3 minX_) (Up3 maxX_))
The N
3
n4 : N (In (Up4 minX_) (Up4 maxX_))
The N
4
n5 : N (In (Up5 minX_) (Up5 maxX_))
The N
5
n6 : N (In (Up6 minX_) (Up6 maxX_))
The N
6
n7 : N (In (Up7 minX_) (Up7 maxX_))
The N
7
n8 : N (In (Up8 minX_) (Up8 maxX_))
The N
8
n9 : N (In (Up9 minX_) (Up9 maxX_))
The N
9
n10 : N (In (Up10 minX_) (Up10 maxX_))
The N
10
n11 : N (In (Up11 minX_) (Up11 maxX_))
The N
11
n12 : N (In (Up12 minX_) (Up12 maxX_))
The N
12
n13 : N (In (Up13 minX_) (Up13 maxX_))
The N
13
n14 : N (In (Up14 minX_) (Up14 maxX_))
The N
14
n15 : N (In (Up15 minX_) (Up15 maxX_))
The N
15
n16 : N (In (Up16 minX_) (Up16 maxX_))
The N
16
Int
intToAbsolute : Basics.Int -> N (Min (Up0 x_))
The Int
's distance from 0
.
This "absolute value" is always ≥ 0
-4
|> N.intToAbsolute
--: N (Min (Up0 x_))
|> N.toInt
--> 4
16 |> N.intToAbsolute |> N.toInt
--> 16
Really only use this if you want the absolute value
badLength =
List.length >> N.intToAbsolute
maybe, there's a solution that never even theoretically deals with unexpected values:
mostCorrectLength =
List.foldl
(\_ -> N.addMin n1 >> N.minSubtract n1)
(n0 |> N.maxToInfinity)
other times, though, like with Array.length
, which isn't O(n)
,
you can escape with for example
arrayLength =
Array.length >> N.intToAtLeast n0
intModBy : N (In (On (Add1 minFrom1_)) (Up maxX To (Add1 maxFrom1PlusX))) -> Basics.Int -> N (In (Up0 remainderMinX_) (Up maxX To maxFrom1PlusX))
Perform modular arithmetic by an N
d ≥ 1
.
That means x % d ≤ d - 1
7
|> N.intModBy n3
--: N (In (Up0 minX_) (Up2 maxX_))
|> N.toInt
--> 1
Works in the typical mathematical way for a negative Int
-7
|> N.intModBy n3
--: N (In (Up0 minX_) (Up2 maxX_))
|> N.toInt
--> 2
Already have an N
? → remainderBy
intToAtLeast : N (In min max_) -> Basics.Int -> N (Min min)
A N (Min ...)
from an Int
;
if the Int < minimum
, minimum
is returned
0
|> N.intToAtLeast n3
--: N (Min (Up3 x_))
|> N.toInt
--> 3
9
|> N.intToAtLeast n3
--: N (Min (Up3 x_))
|> N.toInt
--> 9
You can also use this as an escape hatch
if you know an Int
must be at least minimum
.
But avoid it if you can do better, like
goodLength =
List.foldl
(\_ -> N.addMin n1 >> N.minSubtract n1)
(n0 |> N.maxToInfinity)
To handle the case < minimum
yourself → intIsAtLeast
intToIn : ( N (In minMin (Up minMaxToMaxMin_ To maxMin)), N (In (On maxMin) maxMax) ) -> Basics.Int -> N (In minMin maxMax)
Create a N (In ...)
by clamping an Int
between a minimum & maximum
Int < minimum
, minimum
is returnedInt > maximum
, maximum
is returnedIf you want to handle the cases < minimum
& > maximum
explicitly, use intIsIn
0
|> N.intToIn ( n3, n12 )
--: N (In (Up3 minX_) (Up12 minX_))
|> N.toInt
--> 3
99
|> N.intToIn ( n3, n12 )
|> N.toInt
--> 12
9
|> N.intToIn ( n3, n12 )
|> N.toInt
--> 9
toDigit : Char -> Maybe (N (In (Up0 minX_) (Up9 maxX_)))
toDigit char =
((char |> Char.toCode) - ('0' |> Char.toCode))
|> N.intIsIn ( n0, n9 )
|> Result.toMaybe
Int
compareintIsAtLeast : N (In min max_) -> Basics.Int -> Result Basics.Int (N (Min min))
If the Int ≥
a given minimum
,
return Ok
with the N (Min minimum)
,
else Err
with the input Int
4 |> N.intIsAtLeast n5
--: Result Int (N (Min (Up5 x_)))
--> Err 4
1234 |> N.intIsAtLeast n5 |> Result.map N.toInt
--> Ok 1234
intIsIn : ( N (In minMin (Up minMaxToMaxMin_ To maxMin)), N (In (On maxMin) (Up maxMaxX To maxMaxPlusX)) ) -> Basics.Int -> Result (BelowOrAbove Basics.Int (N (Min (Up maxMaxX To (Add1 maxMaxPlusX))))) (N (In minMin (Up maxMaxX To maxMaxPlusX)))
Compared to a range from a lower to an upper bound, is the Int
in range, BelowOrAbove
?
inputIntParse : Int -> Result String (N (In (Up1 minX_) (Up10 maxX_)))
inputIntParse =
N.intIsIn ( n1, n10 )
>> Result.mapError
(\outOfRange ->
case outOfRange of
N.Below _ ->
"≤ 0"
N.Above _ ->
"≥ 11"
)
0 |> inputIntParse
--> Err "≤ 0"
add : N (In (Up minPlusX To sumMinPlusX) (Up maxPlusX To sumMaxPlusX)) -> N (In (Up minX To minPlusX) (Up maxX To maxPlusX)) -> N (In (Up minX To sumMinPlusX) (Up maxX To sumMaxPlusX))
between70And100 |> N.add n7
--: N (In (Up77 minX_) (Up107 maxX_))
One addend has an unconstrained maximum? → addMin
addMin : N (In (Up minPlusX To sumMinPlusX) addendMax_) -> N (In (Up minX To minPlusX) max_) -> N (Min (Up minX To sumMinPlusX))
To the N
without a known maximum-constraint,
add a number that (only) has information on how to add the minima
atLeast70 |> N.addMin n7
--: N (Min (Up77 x_))
n7 |> N.addMin atLeast70
--: N (Min (Up77 x_))
Use add
if both maxima are known differences as well
If the added minimum is On
, supply the N.minTo
manually
to re-enable adding both minimum types!
atLeast5 |> N.addMin (atLeastOn2 |> N.minTo n2)
--: N (Min (Up7 x_))
subtract : N (In (Down maxPlusX To differenceMaxPlusX) (Down min To differenceMin)) -> N (In (On min) (Up maxX To maxPlusX)) -> N (In (On differenceMin) (Up maxX To differenceMaxPlusX))
From the N
in a range subtract another N
in a range
n6
|> N.subtract n5
--: N (In (On N1) (Up1 x_))
|> N.inToNumber
--> n1 |> N.inToNumber
One of the N
s has no maximum constraint? → N.subtractMin
The subtracted N
can get greater than the current minimum? → N.subtractMax
subtractMin : N (In subtrahendMin_ (Down min To differenceMin)) -> N (In (On min) max) -> N (In (On differenceMin) max)
From an N
with an unknown maximum constraint,
subtract a specific number
atLeast7 |> N.subtractMin n2
--: N (Min (On N5))
atLeast6 |> N.subtractMin between0And5
--: N (Min (On N1))
between6And12 |> N.subtractMin between1And5
--: N (In (On N1) (Up12 maxX_))
Use N.subtract
if you want to subtract an N
in a range
or N.subtractMax
if the subtracted N
can get greater than the current minimum.
subtractMax : N (In (Down max To differenceMax) subtrahendMax_) -> N (In min_ (On max)) -> N (In (Up0 minX_) (On differenceMax))
From an N
,
subtract a number that can get greater than the current minimum
n5 |> N.subtractMax in3To7
--: N (In (Up0 minX_) (On N2))
Use N.subtract
if you want to subtract an N
in a range
or N.subtractMin
if one of the N
s has no maximum constraint
toPower : N (In (On (Add1 exponentMinFrom1_)) exponentMax_) -> N (In min max_) -> N (Min min)
N
Raised to a given power p ≥ 1
→ x ^ p ≥ x
atLeast5 |> N.toPower n2
--: N (Min (Up5 x_))
atLeast2 |> N.toPower n5
--: N (Min (Up2 x_))
remainderBy : N (In (On (Add1 divisorMinFrom1_)) (Up divMaxX To (Add1 divisorMaxFrom1PlusX))) -> N range_ -> N (In (Up0 remainderMinX_) (Up divMaxX To divisorMaxFrom1PlusX))
The remainder after dividing by an N
d ≥ 1
.
That means x % d ≤ d - 1
atMost7 |> N.remainderBy n3
--: N (In (Up0 minX_) (Up2 maxX_))
multiplyBy : N (In (On (Add1 multiplicandMinFrom1_)) multiplicandMax_) -> N (In min max_) -> N (Min min)
Multiply by a given n
≥ 1
.
That means x * n ≥ x
atLeast5 |> N.multiplyBy n2
--: N (Min (Up5 x_))
atLeast2 |> N.multiplyBy n5
--: N (Min (Up2 x_))
divideBy : N (In (On (Add1 divisorMinFrom1_)) divisorMax_) -> N (In min_ max) -> N (In (Up0 minX_) max)
Divide (//
) by an N
d ≥ 1
That means x / d ≤ x
atMost7
|> N.divideBy n3
--: N (In (Up0 minX_) (Up7 maxX_))
|> N.toInt
toAtLeastMin : N (In min max_) -> N range_ -> N (Min min)
Cap the N
to >=
a given new lower limit
n5AtLeast |> N.toAtLeastMin n10
--: N (Min (Up10 x_))
The type doesn't forbid that the lower limit you're comparing against is below the current lower limit
n15AtLeast |> N.toAtLeastMin n10 |> N.toInt
--: N (Min (Up10 x_))
To clamp its maximum, too, toIn
toIn : ( N (In minMin (Up minNewMaxToMaxNewMin_ To maxMin)), N (In (On maxMin) maxMax) ) -> N range_ -> N (In minMin maxMax)
Clamp the number to between both given limits
between5And9 |> N.toIn ( n10, n10 )
--: N (In (Up10 minX_) (Up10 maxX_))
between5And15 |> N.toIn ( n5, n10 )
--: N (In (Up5 minX_) (Up10 maxX_))
between5And12 |> N.toIn ( n10, n12 )
--: N (In (Up10 minX_) (Up12 maxX_))
atLeast5 |> N.toIn ( n5, n10 )
--: N (In (Up5 minX_) (Up10 maxX_))
n15
|> N.toIn ( n10, n15 )
--: N (In (Up10 minX_) (Up15 max_))
|> N.toInt
--> 15
N.intToAtLeast n3 12345
|> N.toIn ( n3, N.intToIn ( n4, n5 ) 5 )
--: N (In (Up3 minX_) (Up5 maxX_))
|> N.toInt
--> 5
There shouldn't be an upper limit? → toAtLeastMin
(The type doesn't forbid that the limits you're comparing against are beyond the current limits)
toInOrAtLeast : ( N (In min (Up newMaxMinToMin_ To newMax)), N (In newMaxMin_ (On newMax)) ) -> N (In min max_) -> N (In min (On newMax))
Cap the N
to <=
a given new upper limit –
but always keep it >=
a given new lower limit.
n5AtLeast |> N.toInOrAtLeast ( n5, n10 )
--: N (In (Up5 x_) (On N10))
n11 |> N.minTo n5 |> N.toInOrAtLeast ( n5, n10 )
--: N (In (Up5 x_) (On N10))
--→ n10
-- ↓ edge cases if you don't set the new minimum as the current one
n7 |> N.toInOrAtLeast ( n6 |> N.minTo n5, n1 |> N.maxTo n10 )
--: N (In (Up5 x_) (On N10))
--→ n7
n5 |> N.toInOrAtLeast ( n6 |> N.minTo n5, n1 |> N.maxTo n10 )
--: N (In (Up5 x_) (On N10))
--→ n6
In general, you always want to prefer toIn
and only use this version for type gymnastics
The type doesn't forbid that the upper limit you're comparing against is above the current upper limit
n10To14 |> N.toInOrAtLeast ( n10, n15 ) |> N.toInt
--: N (In (Up10 x_) (On N15))
Not that you should do it, but if you don't set the minimum to the current minimum,
toInOrAtLeast
behaves just like your regular toIn
:
isAtLeast : N (In minMin (Up minMaxX To (Add1 minMaxFrom1PlusX))) -> N (In min max) -> Result (N (In min (Up minMaxX To minMaxFrom1PlusX))) (N (In minMin max))
Is the N
below than or at least as big as a given number?
vote :
{ age : N (In (On (Add18 minFrom18_)) max_) }
-> Vote
tryToVote { age } =
case age |> N.isAtLeast n18 of
Err _ ->
-- 😓
Nothing
Ok oldEnough ->
vote { age = oldEnough } |> Just
factorial : N (In min_ max_) -> N (Min (Up1 x_))
factorial =
factorialBody
factorialBody : N (In min_ max_) -> N (Min (Up1 x_))
factorialBody x =
case x |> N.isAtLeast n1 of
Err _ ->
n1 |> N.maxToInfinity
Ok atLeast1 ->
factorial (atLeast1 |> N.subtractMin n1)
|> N.multiplyBy atLeast1
(The type doesn't forbid that the lower limit you're comparing against
is below the current minimum or above the current maximum.
→ Err
or Ok
values don't necessarily follow min ≤ max
for N (In min max ...)
Luckily that's not a problem, since the values won't be produced anyway.)
isAtMost : N (In (Up maxMinX To maxMinPlusX) maxMax) -> N (In min max) -> Result (N (In (Up maxMinX To (Add1 maxMinPlusX)) max)) (N (In min maxMax))
Is the N
at most (Ok
) or greater than (Err
) a given number?
goToBelow18Party : { age : N (In min_ (Up maxTo17 To N17)) } -> Snack
tryToGoToBelow18Party { age } =
case age |> N.isAtMost n17 of
Ok below18 ->
goToBelow18Party { age = below18 } |> Just
Err _ ->
Nothing
(The type doesn't forbid that the upper limit you're comparing against
is below the current minimum or above the current maximum.
→ Err
or Ok
values don't necessarily follow min ≤ max
for N (In min max ...)
Luckily that's not a problem, since the values won't be produced anyway.)
The error result of comparing N
s
Above
: greater than what it's compared againstBelow
: less than what it's compared againstValues exist for each condition
is : N (In (Up minX To vsMinPlusX) (Up maxX To (Add1 vsMaxFrom1PlusX))) -> N (In min max) -> Result (BelowOrAbove (N (In min (Up maxX To vsMaxFrom1PlusX))) (N (In (Up minX To (Add1 vsMinPlusX)) max))) (N (In (Up minX To vsMinPlusX) (Up maxX To (Add1 vsMaxFrom1PlusX))))
Is the N
equal to, BelowOrAbove
a given number?
giveAPresent { age } =
case age |> N.is n18 of
Err (N.Below younger) ->
toy { age = younger }
Err (N.Above older) ->
book { age = older }
Ok _ ->
bigPresent
toy : { age : N (In min_ (Up17 maxX_)) } -> Toy
book :
{ age : N (In (On (Add19 minFrom9_)) max_) }
-> Book
(The type doesn't forbid that the number you're comparing against
is below the current minimum or above the current maximum.
→ Err
or Ok
values don't necessarily follow min ≤ max
for N (In min max ...)
Luckily that's not a problem, since the values won't be produced anyway.)
isIn : ( N (In minMin (Up minMaxX To (Add1 minMaxFrom1PlusX))), N (In (Up maxMinX To maxMinPlusX) maxMax) ) -> N (In min max) -> Result (BelowOrAbove (N (In min (Up minMaxX To minMaxFrom1PlusX))) (N (In (Up maxMinX To (Add1 maxMinPlusX)) max))) (N (In minMin maxMax))
Compared to a range from a lower to an upper bound,
is the N
in range or BelowOrAbove
?
isIn3To10 : N (In min_ max_) -> Maybe (N (In (Up3 minX_) (Up10 maxX_)))
isIn3To10 =
N.isIn ( n3, n10 ) >> Result.toMaybe
n9 |> isIn3To10 |> Maybe.map N.toInt
--> Just 9
n12 |> isIn3To10
--> Nothing
(The type doesn't forbid that the limits you're comparing against
are below the current minimum, above the current maximum or in the wrong order.
→ Err
or Ok
values don't necessarily follow min ≤ max
for N (In min max ...)
Luckily that's not a problem, since the values won't be produced anyway.)
Here's some example-cases:
hi < lo < min < max
→ Below | Above
hi < min < lo < max
→ Below | Above
hi < min < max < lo
→ Below | Above
lo < hi < min < max
→ Above
max < hi < min < lo
→ Below
min < hi < lo < max
→ Below | Above
lo < min < hi < max
→ Ok | Above
max < min < hi < lo
→ Below
max < lo < hi < min
→ Below | Ok | Above
← the default caselo < min < max < hi
→ Ok
min < lo < max < hi
→ Ok | Below
min < max < lo < hi
→ Below
.
greater : N range -> N range -> N range
The maximum of both given numbers in the same range
Even though you can just use directly
N.intToIn ( n0, n10 ) 3
|> N.greater (N.intToIn ( n0, n10 ) 1)
|> N.toInt
--> 3
N.intToIn ( n0, n10 ) 3
|> N.greater (N.intToIn ( n0, n10 ) 4)
|> N.toInt
--> 4
this is rather supposed to be used as a primitive to build a structure maximum function
ArraySized.fold Up N.greater
For clamping, try toIn
and toAtLeastMin
instead!
toInt : N range_ -> Basics.Int
Drop the range constraints
to feed another library with its Int
representation
n3
|> N.add n5
|> N.divideBy n3
|> N.toInt
--> 2
toFloat : N range_ -> Basics.Float
Drop the range constraints
to feed another library with its Float
representation
Equivalent to
toInt |> toFloat
toString : N range_ -> String
Drop the range constraints
to feed another library with its String
representation
Equivalent to
toInt |> String.fromInt
inToNumber : N (In (On min) (On max)) -> N (In min max)
Number with On
range → number with equatable range
If you want an equatable Min ...
N
, you instead only need minToNumber
inToOn : N (In min max) -> N (In (On min) (On max))
N
with equatable number range
→ N
with On
range to be altered, compared, ...
If you want a Min (On ...)
N
, you instead only need minToOn
minToNumber : N (In (On min) max) -> N (In min max)
N
with On
minimum
→ N
with equatable minimum number
You'll usually use this to convert to an equatable Min ...
N
minToOn : N (In min max) -> N (In (On min) max)
N
with equatable minimum number
→ N
with On
minimum
You'll usually use this to convert to a Min (On ...)
N
maxToNumber : N (In min (On max)) -> N (In min max)
N
with On
maximum
→ N
with equatable maximum number
maxToOn : N (In min max) -> N (In min (On max))
N
with an equatable maximum number
→ N
with On
maximum
minTo : N (In minNew (Up minNewMaxToMin_ To min)) -> N (In (On min) max) -> N (In minNew max)
Set its minimum to a given (lower) one
[ atLeast3, atLeast4 ]
Elm complains:
But all the previous elements in the list are:
N (Min N3)
[ atLeast3
, atLeast4 |> N.minTo n3
]
To decrease its minimum by a relative amount, minSubtract
minSubtract : N (In maxIncreasedMin_ (Down minPlusX To minDecreasedPlusX)) -> N (In (Up x To minPlusX) max) -> N (In (Up x To minDecreasedPlusX) max)
Decrease its minimum by a given relative amount.
To set its minimum to a specific absolute value, minTo
minEndsSubtract : N (In (Down minX To minXDecreased) (Down minPlusX To minPlusXDecreased)) -> N (In (Up minX To minPlusX) max) -> N (In (Up minXDecreased To minPlusXDecreased) max)
Decrease the start and end of its min
difference
n3
--: N (In (Up3 (Add2 minX_)) (Up3 maxX_))
|> N.minEndsSubtract n2
--: N (In (Up5 minX_) (Up5 maxX_))
maxEndsSubtract
has an example of where this can be useful.
minTo0 : N (In min_ max) -> N (In (Up0 minX_) max)
Set the minimum as 0, without relying on the minimum being fixed
like the more general minTo
maxTo : N (In (On newMaxMin) newMax) -> N (In min (Up maxToNewMaxMin_ To newMaxMin)) -> N (In min newMax)
Set its maximum to a given (lower) one.
This can help "resetting" an argument's maximum to make it fit into functions that require a higher maximum.
Since you should type arguments and stored types as broad as possible
onlyAtMost18 : N (In min_ (Up maxTo18_ To N18)) -> ...
onlyAtMost18 between3And8 -- works
once you implement onlyAtMost18
, you might use the n
in onlyAtMost19
:
onlyAtMost18 n =
-- onlyAtMost19 n → error
onlyAtMost19 (n |> N.maxTo n18)
To increase its maximum by a relative amount, maxAdd
maxToInfinity : N (In min max_) -> N (Min min)
On N (In min max)
's type,
allow max
to go up to infinity to get a N (Min min)
between3And10 |> N.maxToInfinity
--: N (Min (Up3 x_))
Use it to unify different types of number minimum constraints like
[ atLeast1, between1And10 ]
elm complains:
But all the previous elements in the list are:
N (Min (Up1 x_))
[ atLeast1
, between1And10 |> N.maxToInfinity
]
maxAdd : N (In increaseMin_ (Up maxPlusX To maxIncreasedPlusX)) -> N (In min (Up maxX To maxPlusX)) -> N (In min (Up maxX To maxIncreasedPlusX))
Increase its maximum by a given relative amount.
To set its maximum to a specific absolute value, N.maxTo
maxEndsSubtract : N (In (Down maxPlusX To maxPlusXDecreased) (Down maxX To maxXDecreased)) -> N (In min (Up maxX To maxPlusX)) -> N (In min (Up maxXDecreased To maxPlusXDecreased))
Decrease the start and end of its max
difference
n3
--: N (In (Up3 minX_) (Up3 (Add2 maxX_)))
|> N.addStart n2
--: N (In (Up5 minX_) (Up5 maxX_))
Huh... One rare use-case is avoiding an extra type parameter:
With extra type parameter:
{-| Gives each index a label. Access using `partIn`
-}
type alias Group record lastIndex count =
{ record : record
, parts : ArraySized String (Exactly (On count))
, lastIndex : N (In (On N0) lastIndex)
}
addPart :
String
->
(Group
(N (In (On N0) (Up x To lastIndexPlusX)) -> record)
(Up x To lastIndexPlusX)
count
-> Group record (Up x To (Add1 lastIndexPlusX)) (Add1 count)
)
addPart partName groupSoFar =
{ record = groupSoFar.record groupSoFar.lastIndex
, parts = groupSoFar.parts |> ArraySized.push partName
, lastIndex = groupSoFar.lastIndex |> N.add n1
}
partIn :
Group record i_ (Add1 lastIndex)
-> (record -> N (In (On N0) (Up x_ To lastIndex)))
-> String
partIn group field =
group.parts |> ArraySized.element ( Up, group.record |> field )
If we change Group record lastIndex count
to keep only one of both, we have a problem:
All indexes in the record
are dependent on the same maximum which now is On
.
That means that lower indexes aren't accepted by partIn
anymore. The fix:
addPart :
String
->
(GroupBeingBuilt
(N (In (On N0) (Up (Add1 xFrom1) To lastIndex)) -> record)
(Up (Add1 xFrom1) To lastIndex)
count
-> GroupBeingBuilt record (Up xFrom1 To lastIndex) (Add1 count)
)
addPart partName groupSoFar =
{ record = groupSoFar.record groupSoFar.lastIndex
, parts = groupSoFar.parts |> ArraySized.push partName
, lastIndex = groupSoFar.lastIndex |> N.add n1 |> N.maxEndsSubtract n1 |> N.minTo n0
}
type alias GroupComplete record count =
Group record (On count) count
The really nice thing is that as we finish, the start of minimum difference is N0
,
which makes this an On
Consider this an advanced technique for packages that use
allowable-state
.
Any questions
isAtLeast1 : N (In (On (N0OrAdd1 n0PossiblyOrNever minFrom1_)) max) -> Result n0PossiblyOrNever (N (In (Up1 minX_) max))
Transfer the knowledge about whether n0
is a possible value
stackRepeat :
element
-> N (In (On (N0OrAdd1 possiblyOrNever minFrom1_)) max_)
-> Emptiable (Stacked element) possiblyOrNever
stackRepeat toRepeat length =
case length |> N.isAtLeast1 of
Err possiblyOrNever ->
Emptiable.Empty possiblyOrNever
Ok lengthAtLeast1 ->
Stack.topBelow
toRepeat
(List.repeat
(lengthAtLeast1 |> N.subtract n1 |> N.toInt)
toRepeat
)
stackLength :
Emptiable (Stacked element) possiblyOrNever
-> N (Min (On (N0OrAdd1 possiblyOrNever N0)))
stackLength =
\stack ->
case stack of
Emptiable.Empty possiblyOrNever ->
-- adapt the variable minimum
n0 |> N.min0Adapt (\_ -> possiblyOrNever) |> N.maxToInfinity
Emptiable.Filled (TopBelow ( _, belowTop )) ->
belowTop
|> List.length
|> N.intToAtLeast n0
|> N.add n1
-- downgrade the minimum
|> N.min0Adapt never
using N.min0Adapt
Stack and Emptiable are part of emptiness-typed
Cool, right?
min0Adapt : (possiblyOrNever -> adaptedPossiblyOrNever) -> N (In (On (N0OrAdd1 possiblyOrNever minFrom1)) max) -> N (In (On (N0OrAdd1 adaptedPossiblyOrNever minFrom1)) max)
Change the possiblyOrNever
type for the case that its min
is 0
never
allows you to adapt any variable,
\_ -> yourVariablePossiblyOrNever
swaps it for your given variable
stackLength :
Emptiable (Stacked element) possiblyOrNever
-> N (Min (On (N0OrAdd1 possiblyOrNever N0)))
stackLength =
\stack ->
case stack of
Emptiable.Empty possiblyOrNever ->
n0
-- adapt the variable minimum
|> N.min0Adapt (\_ -> possiblyOrNever)
-- allow a different min - 1 type
|> N.minAtLeast1Never
|> N.maxToInfinity
Emptiable.Filled (TopBelow ( _, belowTop )) ->
belowTop
|> List.length
|> N.intToAtLeast n0
|> N.add n1
-- downgrade the minimum
|> N.min0Adapt never
using isAtLeast1
, minAtLeast1Never
.
Stack and Emptiable are part of emptiness-typed
with (\_ -> Possible)
it's just a worse version of minSubtract
that might be useful in ultra rare situations
minSubtract1IfPossible :
N (In (On (N0OrAdd1 possiblyOrNever minFrom1)) max)
-> N (In (On (N0OrAdd1 Possibly minFrom1)) max)
minSubtract1IfPossible =
N.min0Adapt (\_ -> Possibly)
minAtLeast1Never : N (In (On (N0OrAdd1 possiblyOrNever Basics.Never)) max) -> N (In (On (N0OrAdd1 possiblyOrNever minFrom1_)) max)
For the case that its min
is 1 + ..., allow adapting any variable.
This is possible because we currently have a minimum that is Never
>= 1
stackLength :
Emptiable (Stacked element) possiblyOrNever
-> N (Min (On (N0OrAdd1 possiblyOrNever N0)))
stackLength =
\stack ->
case stack of
Emptiable.Empty possiblyOrNever ->
n0
-- adapt the variable minimum
|> N.min0Adapt (\_ -> possiblyOrNever)
-- allow a different type for min from 1
|> N.minAtLeast1Never
|> N.maxToInfinity
Emptiable.Filled (TopBelow ( _, belowTop )) ->
belowTop
|> List.length
|> N.intToAtLeast n0
|> N.add n1
-- downgrade the minimum
|> N.min0Adapt never
using isAtLeast1
, min0Adapt
Anything that can't be expressed with the available operations? → issue/PR
Internal parts you can safely access and transform
While the internally stored Int
can't directly be guaranteed to be in bounds by elm,
the minimum and maximum
must be built as actual values checked by the compiler.
No shenanigans like runtime errors for impossible cases
Having those exposed can be useful when building extensions to this library like
range : N range -> range
Its limits
containing both its min
and its max
import Possibly exposing (Possibly(..))
N.intToIn ( n3, n5 ) 4
--: N (In (Up3 minX_) (Up5 maxX_))
|> N.minTo n2
--: N (In (Up2 minX_) (Up5 maxX_))
|> N.range
--: In (Up2 minX_) (Up5 maxX_)
|> N.rangeInToNumber
--: In N2 N5
|> N.rangeMin
--: N2
--> N.Add1 (N.Add1 (N.N0 Possible))
min : N (In min maximum_) -> min
The smallest allowed number promised by the range type as its representation as a difference
max : N (In min_ max) -> max
The greatest allowed number promised by the range type as its representation as a difference
differenceAdd : Up middle To high -> Up low To middle -> Up low To high
Chain the difference Up
to a higher natural number
differenceSubtract : Down high To middle -> Up low To high -> Up low To middle
Chain the difference Down
to a lower number
addDifference : Up low To high -> low -> high
Increase a number by a given difference
successor : n -> Add1 n
successor =
-- FYI: equivalent to Add1
N.addDifference (n1 |> N.min)
n10 |> N.min |> N.onToNumber |> successor
--> n11 |> N.min |> N.onToNumber
subtractDifference : Down high To low -> high -> low
Decrease the natural number by a given difference
predecessor : Add1 predecessor -> predecessor
predecessor =
N.subtractDifference (n1 |> N.min)
n10 |> N.min |> N.onToNumber |> predecessor
--> n9 |> N.min |> N.onToNumber
Base type of N0
, Add1 n
following allowable-state
:
Is the parameter possiblyOrNever
set to Never
like in
type alias Add1 n =
N0aOrAdd1 Never n
N0
is impossible to construct
Is the parameter possiblyOrNever
set to Possibly
like in
type alias N0 =
N0OrAdd1 Possibly Never
N0
is a possible value
inRange : ( In minMin (Up minMaxToMaxMin_ To maxMin), In (On maxMin) maxMax ) -> In minMin maxMax
Create a range from the lowest possible representation of a given lower range to the highest possible representation of a given higher range
minRange : min -> Min min
Create a range with a given representation as the minimum
and Infinity
as the maximum
N.intToIn ( n3, n6 ) 5
|> N.min
|> N.minRange
--: Min (Up3 x)
maxRange : max -> In (Up0 newMinX_) max
Create a range with minimum set to 0 and a given maximum
exactlyRange : limitRepresentation -> In limitRepresentation limitRepresentation
Create a range with a given representation = minimum = maximum
N.intToIn ( n3, n6 ) 5
|> N.min
|> N.exactlyRange
--: In (Up3 x) (Up3 x)
rangeMin : In min max_ -> min
The range's lowest possible representation
rangeMax : In min_ max -> max
The range's highest possible representation
rangeAdd : In (Up minPlusX To minIncreasedPlusX) (Up maxPlusX To maxIncreasedPlusX) -> In (Up minX To minPlusX) (Up maxX To maxPlusX) -> In (Up minX To minIncreasedPlusX) (Up maxX To maxIncreasedPlusX)
Add a given difference to its minimum and maximum
rangeSubtract : In (Down maxPlusX To maxDecreasedPlusX) (Down min To minDecreased) -> In (On min) (Up maxX To maxPlusX) -> In (On minDecreased) (Up maxX To maxDecreasedPlusX)
Subtract its minimum and maximum by a given difference
rangeMinSubtract : Down minPlusX To minDecreasedPlusX -> In (Up x To minPlusX) max -> In (Up x To minDecreasedPlusX) max
Subtract its minimum by a given difference
rangeMaxSubtract : Down maxPlusX To maxDecreasedPlusX -> In min_ (Up x To maxPlusX) -> In (Up0 minX_) (Up x To maxDecreasedPlusX)
Subtract its maximum by a given difference and set the minimum to 0
rangeMaxAdd : Up maxPlusX To maxIncreasedPlusX -> In min (Up maxX To maxPlusX) -> In min (Up maxX To maxIncreasedPlusX)
Add a given difference to its maximum
rangeMinEndsSubtract : In (Down minX To minXDecreased) (Down minPlusX To minPlusXDecreased) -> In (Up minX To minPlusX) max -> In (Up minXDecreased To minPlusXDecreased) max
Decrease the start and end of its rangeMin
difference
n3
|> N.range
--: In (Up3 (Add2 minX_)) (Up3 maxX_)
|> N.rangeMinEndsSubtract (n2 |> N.range)
--: In (Up5 minX_) (Up5 maxX_)
See maxEndsSubtract
for details and examples
rangeMaxEndsSubtract : In (Down maxPlusX To maxPlusXDecreased) (Down maxX To maxXDecreased) -> In min (Up maxX To maxPlusX) -> In min (Up maxXDecreased To maxPlusXDecreased)
Decrease the start and end of its rangeMax
difference
n3
|> N.range
--: In (Up3 minX_) (Up3 (Add2 maxX_))
|> N.rangeMaxEndsSubtract (n2 |> N.range)
--: In (Up5 minX_) (Up5 maxX_)
See maxEndsSubtract
for details and examples
rangeMinTo : In newMin (Up newMinMaxToMin_ To min) -> In (On min) max -> In newMin max
Set its minimum to a given (lower) one
rangeMaxTo : In (On newMaxMin) maxNew -> In min (Up maxToNewMaxMin_ To newMaxMin) -> In min maxNew
Set its maximum to a given (higher) one
number0Adapt : (n0PossiblyOrNever -> adaptedN0PossiblyOrNever) -> N0OrAdd1 n0PossiblyOrNever from1 -> N0OrAdd1 adaptedN0PossiblyOrNever from1
Change the possiblyOrNever
type
for the case that the N0OrAdd1
is N0
numberFrom1Map : (from1 -> mappedFrom1) -> N0OrAdd1 n0PossiblyOrNever from1 -> N0OrAdd1 n0PossiblyOrNever mappedFrom1
Change the type
for the case that the N0OrAdd1
is Add1 from1
on0Adapt : (possiblyOrNever -> adaptedPossiblyOrNever) -> On (N0OrAdd1 possiblyOrNever from1) -> On (N0OrAdd1 adaptedPossiblyOrNever from1)
Change the possiblyOrNever
type
for the case that its N0OrAdd1
representation is N0
onFrom1Map : (from1 -> mappedFrom1) -> On (N0OrAdd1 n0PossiblyOrNever from1) -> On (N0OrAdd1 n0PossiblyOrNever mappedFrom1)
Change the type
for the case that the N0OrAdd1
is Add1 from1
rangeIsAtLeast1 : N (In (On (N0OrAdd1 n0PossiblyOrNever minFrom1_)) max) -> Result n0PossiblyOrNever (In (Up1 minX_) max)
Transfer the knowledge about whether n0
is a possible value
rangeMin0Adapt : (possiblyOrNever -> adaptedPossiblyOrNever) -> In (On (N0OrAdd1 possiblyOrNever minFrom1)) max -> In (On (N0OrAdd1 adaptedPossiblyOrNever minFrom1)) max
Change its minimum's possiblyOrNever
type
for the case that the N0OrAdd1
is N0
rangeMinAtLeast1Never : In (On (N0OrAdd1 possiblyOrNever Basics.Never)) max -> In (On (N0OrAdd1 possiblyOrNever minFrom1_)) max
For the case that its min
is 1 + ..., allow adapting any variable.
This is possible because we currently have a minimum that is Never
>= 1
onToNumber : On representedNumber -> representedNumber
The N0OrAdd1
represented by this On
difference
import Possibly exposing (Possibly(..))
N.intToIn ( n3, n10 ) 5
|> N.min
|> N.onToNumber
--> N.Add1 (N.Add1 (N.Add1 (N.N0 Possible)))
useful
to preserve emptiness knowledge
predecessor :
N0OrAdd1 possiblyOrNever from1
-> Emptiable from1 possiblyOrNever
predecessor =
\number ->
case number of
N.N0 possiblyOrNever ->
Emptiable.Empty possiblyOrNever
N.Add1 predecessor ->
predecessor |> Emptiable.filled
as a tag
type Element index
= Element index
element :
N (Exactly (On index))
-> Mapping (List element) (Element index) (Maybe element)
element index =
Typed.tag
(Element (index |> N.min |> N.onToNumber))
List.Extra.getAt
Can be altered with addDifference
, subtractDifference
.
To preserve the ability to turn the number into an Int
, use onToNumber
toOn : asNumber -> On asNumber
equatable number → On
rangeInToNumber : In (On min) (On max) -> In min max
In
(On ...) (On ...)
→ equatable In
rangeInToOn : In min max -> In (On min) (On max)
equatable In
→ In
(On ...) (On ...)
rangeMinToNumber : In (On min) max -> In min max
Make range's On
minimum equatable
rangeMinToOn : In min max -> In (On min) max
Make range's equatable minimum On
rangeMaxToNumber : In min (On max) -> In min max
Make range's On
maximum equatable
rangeMaxToOn : In min max -> In min (On max)