for more information visit the package's GitHub page
Package contains the following modules:
Natural number ≥ 0 that has extra information about its range at compile-time
toHexChar
toHexChar : Int -> Char
Int
between 0 & 15 is expectedtoHexChar
has to handle the cases where the argument isn't between 0 & 15Maybe
which will be carried throughout your program'?'
or even worse '0'
Int
range promise of the argument is lost after the operationwith bounded-nat
:
toHexChar : N (In min_ (Up maxTo15_ To N15)) -> Char
The argument type says: Give me an integer ≥ 0 N
In
range
- ≥ 0
→ any minimum allowed → min_
type variable that's only used once
- ≤ 15
→ if we increase some number (maxTo15_
type variable that's only used once) by the argument's maximum, we get N15
Users can prove this by explicitly
using specific values
elm
red = rgbPercent { r = n100, g = n0, b = n0 } --👍
n7 |> N.subtract n1 |> N.divideBy n2 |> toHexChar --→ '3'
handling the possibility that a number isn't in the expected range
elm
toPositive : Int -> Maybe (N (Min (Up1 x_)))
toPositive =
N.intIsAtLeast n1 >> Result.toMaybe
clamping
elm
floatPercent float =
float * 100 |> round |> N.intToIn ( n0, n100 )
there are more ways, but you get the idea 🙂
toDigit
toDigit : Char -> Maybe Int
You might be able to do anything with this Int
value, but you lost useful information:
toDigit :
Char -> Maybe (N (In (Up0 minX_) (Up9 maxX_)))
The type of an N
value will reflect how much you and the compiler know
factorial
intFactorial : Int -> Int
intFactorial x =
case x of
0 ->
1
non0 ->
non0 * intFactorial (non0 - 1)
This forms an infinite loop if we call intFactorial -1
...
Let's disallow negative numbers here (& more)!
import N exposing (N, In, Min, Up1, n1, n4)
-- for every `n ≥ 0`, `n! ≥ 1`
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 xMin1 ->
-- xMin1 : N (Min ..1..), so xMin1 - 1 ≥ 0
factorial (xMin1 |> N.subtractMin n1)
|> N.multiplyBy xMin1
factorial n4 |> N.toInt --> 24
≥ 1
Separate factorial
& factorialBody
are needed because there's no support for polymorphic recursion 😢
We can do even better!
!19
is already >
the maximum safe Int
2^53 - 1
safeFactorial : N (In min_ (Up maxTo18_ To N18)) -> N (Min (Up1 x_))
safeFactorial =
factorial
No extra work
keep as much type information as possible and drop it only where you need to: "Wrap early, unwrap late"
keep argument types as broad as possible
like instead of
elm
charFromCode : N (Min min_) -> Char
which you should never do, allow maximum-constrained numbers to fit as well:
elm
charFromCode : N (In min_ max_) -> Char
typesafe-array
shows thatN (In ...)
is very useful as an indexIn
, Min
, Exactly
, ... can also describe a length