In Elm (and many other languages, I assume, I'm just most familiar with Elm) there's a pattern called "opaque data type". [0] You make a file that contains the type and its constructor but you don't export the constructor. You only export the getter and setter methods. This ensures that if you properly police the methods of that one short file, everywhere else in your program that the type is used is guaranteed by the type system to have a number between zero and one.
-- BetweenZeroAndOne.elm
module BetweenZeroAndOne exposing (get, set)
type BetweenZeroAndOne
= BetweenZeroAndOne Float
set : Float -> BetweenZeroAndOne
set value = BetweenZeroAndOne (Basics.clamp 0.0 1.0 value)
get : BetweenZeroAndOne -> Float
get (BetweenZeroAndOne value) = value
-- BetweenZeroAndOne.elm
module BetweenZeroAndOne exposing (get, set)
type BetweenZeroAndOne = BetweenZeroAndOne Float
set : Float -> BetweenZeroAndOne set value = BetweenZeroAndOne (Basics.clamp 0.0 1.0 value)
get : BetweenZeroAndOne -> Float get (BetweenZeroAndOne value) = value
[0] https://en.wikipedia.org/wiki/Opaque_data_type#:~:text=In%20....