lue-bird/elm-bounded-nat/1.0.0

NOTE: the latest version is 35.0.0

Nat

type alias Nat range =
Nat range

A bounded natural number (>= 0).

value / return types

-- >= 4
Nat (ValueMin Nat4)


-- 2 <= nat <= 12
Nat (ValueIn Nat2 Nat12)


-- = 3, & 3, described as a difference
Nat (N Nat3 (Nat3Plus more) (Is a To (Nat3Plus a)) (Is b To (Nat3Plus b)))

function argument types

-- >= 4
Nat (In (Nat4Plus minMinus4) max maybeN)


-- 4 <= nat <= 5
Nat (In (Nat4Plus minMinus4) Nat15 maybeN)


-- any, just >= 0
Nat range


-- Not constuctable
Nat Banana

create

abs : Int -> Nat (ValueMin Nat0)

The absolute value of an Int, which is at least Nat0.

MinNat.abs 16 --> Nat 16


MinNat.abs -4 --> Nat 4

Really only use this if you want the absolute value.

badLength list =
    List.length >> MinNat.abs


goodLength =
    List.foldl
        (\_ ->
            MinNat.addN nat1
                >> InNat.lowerMin nat0
        )
        (nat0 |> NNat.toMin)

If something like this isn't possible, use MinNat.intAtLeast!

Nat (In firstMin lastMin firstMaybeN)
-> Nat (In lastMin lastMax lastMaybeN)
-> List (Nat (ValueIn firstMin lastMax))

Nat (In ...)s from a first to a last value.

from3To10 : List (Nat (ValueIn Nat3 (Nat10Plus a)))
from3To10 =
    InNat.range nat3 nat10


from3ToAtLeast10 : List (Nat (ValueMin Nat3))
from3ToAtLeast10 =
    InNat.range nat3 atLeast10

The resulting List is never empty.

Nat (In firstMin lastMin firstMaybeN)
-> Nat (In lastMin lastMax lastMaybeN)
-> Generator (Nat (ValueIn firstMin lastMax))

Generate a random Nat (In ...) in a range.

modify

Nat (In (Nat1Plus powMinMinus1) powMax powMaybeN)
-> Nat (In min max maybeN)
-> Nat (ValueMin min)

The Nat (ValueMin ...) ^ a Nat (ValueMin ...). We know that if a >= 1 → x ^ a >= x

atLeast5 |> MinNat.toPower nat2
--> Nat 25 of type Nat (ValueMin Nat5)


atLeast2 |> MinNat.toPower nat5
--> Nat 25 of type Nat (ValueMin Nat2)
Nat (In (Nat1Plus divMinMinus1) divMax divMaybeN)
-> Nat (In min max maybeN)
-> Nat (ValueIn Nat0 max)

The remainder after division.

  • % 0 is impossible
  • x % d is at most x
atMost7 |> InNat.remainderBy nat3
--> Nat 1 of type Nat (In Nat0 (Nat7Plus a))
mul :
Nat
(In
(Nat1Plus minMultipliedMinus1)
maxMultiplied
multipliedMaybeN
)
-> Nat (In min max maybeN)
-> Nat (ValueMin min)

Multiply by a Nat (In ...) >= 1. we know that if a >= 1, x * a >= x.

atLeast5  |> MinNat.mul nat2
--> Nat 10 of type Nat (ValueMin Nat5)


atLeast2 |> MinNat.mul nat5
--> Nat 10 of type Nat (ValueMin Nat2)

The maximum value of both factors can be Infinity.

div :
Nat (In (Nat1Plus divMinMinus1) divMax divMaybeN)
-> Nat (In min max maybeN)
-> Nat (ValueIn Nat0 max)

Divide (//) by a Nat (In ...).

  • / 0 is impossible

  • x / d is at most x

atMost7
    |> InNat.div nat3
--> Nat 2 of type Nat (ValueIn Nat0 (Nat7Plus a))

transform

toInt : Nat range -> Int

Convert a Nat to an Int.

nat4 |> Nat.toInt --> 4
nat4 |> NNat.toIn |> Nat.toInt --> 4
nat4 |> NNat.toMin |> Nat.toInt --> 4


compare : Nat range -> Nat range -> Order
compare a b =
    compare (Nat.toInt a) (Nat.toInt b)
bi : (Int -> Int -> result) -> Nat aRange -> Nat bRange -> result

Use the Int values of two Nats to return a result.

Nat.bi (>=) nat5 nat4 --> True


Nat.bi (>=) nat5 nat40 --> False

Note, that you must give the Nats in the same order you would give Ints.

Don't overuse this.

compare

theGreater : Nat range -> Nat range -> Nat range

The greater of 2 Nats. Works just like Basics.max.

Nat.theGreater atLeast3
    (atLeast4 |> InNat.lowerMin nat3)
--> Nat 4
theSmaller : Nat range -> Nat range -> Nat range

The smaller of 2 Nats. Works just like Basics.min.

Nat.theSmaller atLeast3
    (atLeast4 |> InNat.lowerMin nat3)
--> Nat 3
{ first : Nat (In minFirst last firstMaybeN)
, last : Nat (In last lastPlusA lastMaybeN)
}
-> { less : () -> result
, greater : Nat (ValueMin (Nat1Plus last)) -> result
, inRange : Nat (ValueIn minFirst lastPlusA) -> result
}
-> Int
-> result

An Int compared to a range from first to last.

rejectOrAcceptUserInt =
    isIntInRange nat1 nat100
        { less = Err "must be >= 1"
        , greater = \_-> Err "must be <= 100"
        , inRange = Ok
        }


rejectOrAcceptUserInt (NNat.toIn nat0)
--> Err "must be >= 1"
isIntAtLeast : Nat (In min max maybeN) -> Int -> Maybe (Nat (ValueMin min))

If the Int >= a minimum, Just the Nat (Min minimum), else Nothing.

4 |> Nat.isIntAtLeast nat5 --> Nothing


1234 |> Nat.isIntAtLeast nat5 --> Just (Nat 1234)

clamp

intAtLeast : Nat (In min max maybeN) -> Int -> Nat (ValueMin min)

A Nat (Min ...) from an Int; if the Int < minimum, minimum is returned.

9 |> Nat.intAtLeast (nat3 |> NNat.toMin)
--> Nat 9


0 |> Nat.intAtLeast (nat3 |> NNat.toMin)
--> Nat 3

You can also use this if you know an Int must be at least minimum.

But avoid it if you can do better, like

goodLength =
    List.foldl
        (\_ ->
            MinNat.addN nat1
                >> InNat.lowerMin nat0
        )
        (nat0 |> InNat.toMin)

If you want to handle the case < minimum yourself, use Nat.isIntAtLeast.

Nat (In min firstMax maybeN)
-> Nat (In firstMax max upperMaybeN)
-> Int
-> Nat (ValueIn min max)

A Nat (In ...) from an Int, clamped between a minimum & maximum.

  • if the Int < minimum, minimum is returned
  • if the Int > maximum, maximum is returned
clampBetween3And12 =
    Nat.intInRange nat3 nat12

9 |> clampBetween3And12 --> Nat 9

0 |> clampBetween3And12 --> Nat 3

99 |> clampBetween3And12 --> Nat 12

If you want to handle the cases < minimum & > maximum explicitly, use isIntInRange.

drop information

Nat (In lowerMin min lowerMaybeN)
-> Nat (In min max maybeN)
-> Nat (ValueIn lowerMin max)

Set the minimum lower.

[ atLeast3, atLeast4 ]

Elm complains:

But all the previous elements in the list are: Nat (ValueMin Nat3)

[ atLeast3
, atLeast4 |> MinNat.lowerMin nat3
]
toMin : Nat (In min max maybeN) -> Nat (ValueMin min)

Convert an exact Nat (In min ...) to a Nat (ValueMin min).

in4To10 |> NNat.toMin
--> is of type Nat (ValueMin Nat4)

There is only 1 situation you should use this.

To make these the same type.

[ atLeast1, in1To10 ]

Elm complains:

But all the previous elements in the list are: Nat (ValueMin Nat1)

[ atLeast1
, in1To10 |> InNat.toMin
]
Nat (N max (Is a To atLeastMax) x)
-> Nat (In min max maybeN)
-> Nat (ValueIn min atLeastMax)

Make it fit into functions with require a higher maximum.

You should design type annotations as general as possible.

onlyAtMost18 : Nat (In min Nat18 maybeN)


onlyAtMost18 between3And8 --fine

But once you implement onlyAtMost18, you might use the value in onlyAtMost19.

onlyAtMost18 value =
    -- onlyAtMost19 value --error :(
    onlyAtMost19
        (value |> InNat.maxIs nat18 {- works :) -})

lowerMin is also handy in those situations.