indique/elm-bounded-nat/9.1.0

NOTE: the latest version is 13.0.0

Nat

type alias Nat range =
Nat range

A bounded natural number (>= 0).

-- >= 4
Nat (Min Nat4)


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


-- = 3
Nat (Only Nat3)


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


-- either one of the above
Nat range


-- Not constuctable
Nat Banana

from Int

abs : Int -> Nat (Min 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 |> NNat.toIn)
        )
        (nat0 |> NNat.toMin)

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

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
    (nat3 |> NNat.toMin)
    (nat4 |> NNat.toMin |> MinNat.lowerMin (nat3 |> NNat.toIn))
--> Nat 4
theSmaller : Nat range -> Nat range -> Nat range

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

Nat.theSmaller
    (nat3 |> NNat.toMin)
    (nat4 |> NNat.toMin |> MinNat.lowerMin (nat3 |> NNat.toIn))
--> Nat 3
{ first : Nat (In minFirst last)
, last : Nat (In last lastPlusA)
}
-> { less : () -> result
, greater : Nat (Min (Nat1Plus last)) -> result
, inRange : Nat (In minFirst lastPlusA) -> result
}
-> Int
-> result

An Int compared to a range from first to last.

rejectOrAcceptUserInt =
    isIntInRange (nat1 |> NNat.toIn) (nat100 |> NNat.toIn)
        { 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) -> Int -> Maybe (Nat (Min min))

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

4 |> Nat.isIntAtLeast (nat5 |> NNat.toIn) --> Nothing


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

clamp

intAtLeast : Nat (In min max) -> Int -> Nat (Min 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 |> NNat.toIn)
        )
        (nat0 |> NNat.toMin)

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

Nat (In min firstMax)
-> Nat (In firstMax max)
-> Int
-> Nat (In 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 |> NNat.toIn) (nat12 |> NNat.toIn)

9 |> clampBetween3And12 --> Nat 9

0 |> clampBetween3And12 --> Nat 3

99 |> clampBetween3And12 --> Nat 12

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