>This would be a nice fix to the Radians / Degrees issue too. Every
language seems to settle on one or the other as "the base unit" but
newcomers have to learn the assumption or face bad accidental outputs.
Yes, `degrees`, `radians`, and `turns` in `Basics` suffer the same problem.
>F# is kind of radical in that it has units.
I didn't know this! (I have heard of F#, but I had never used or read some
of its code.) It pleases me to know that I'm not the only one to think that
is a problem, and that it can be solved by this solution! (F#'s
implementation seems slightly different from what I am imagining, but close
enough.)
I'm curious though, does F# use its unit/measure types widely? or do common
library functions (like those about time, angles, etc) still take a raw
float type where it could take a unit/measure float type? How often do
common 3rd-party libraries use this feature? How often do average-joe
programmers use this feature?
>Could possible do it 'now' with
>...
>If you do not expose the constructor of the type then it should be a fully
opaque type, only able to be constructed via things like `milliseconds 500`
or so.
As a work-around that uses only current features, I like this. It's an
improvement over the current system of just having `Time` be an alias of
`Float`. (Heck, `Angle` isn't even an alias! The angle functions'
signatures are just `Float -> Float`!)
On Thursday, July 28, 2016 at 3:13:27 PM UTC-5, OvermindDL1 wrote:
>
> Could possible do it 'now' with
>
> ```elm
> type Time
> = Time_Value Float
>
> milliseconds m = seconds <| m/1000
>
> seconds s = Time_Value s
>
> minutes m = seconds <| m*60
>
> from_json json =
> Json.Decode.decodeString Json.Decode.float json |> Result.map (\t ->
> Time_Value t)
>
> to_seconds (Time_Value t) = t
>
> to_minutes t = 60 * (to_seconds t)
>
> to_json t = Json.Encode.float <| to_seconds t
> ```
>
> If you do not expose the constructor of the type then it should be a fully
> opaque type, only able to be constructed via things like `milliseconds 500`
> or so.
>
>
> On Thursday, July 28, 2016 at 12:42:44 PM UTC-6, John Bugner wrote:
>>
>> In the time library (
>> package.elm-lang.org/packages/elm-lang/core/4.0.3/Time ), there are many
>> functions under the "Units" heading. Under the function `millisecond`, it
>> says:
>> >Units of time, making it easier to specify things like a half-second
>> (500 * millisecond) without remembering Elm’s underlying units of time.
>> I find this underwhelming, because nothing forces me to use these unit
>> functions. I could write `every 5 toMsg` and the compiler will not stop me.
>> How long of a time am I actually specifying? Probably 5 milliseconds,
>> because I infer that it's probably using the same unit as JavaScript, but I
>> can't know for sure. A beginner might think 5 seconds, because it's the
>> unit that has no prefixes, or 5 minutes if 5 minutes seems appropriate to
>> what the application does. This is very bad; There should never be doubt
>> about what unit is being used, and the compiler should enforce this unit
>> correctness. Currently, Elm can't do this, because `Time` is just an alias
>> for `Float`.
>>
>> To prevent this kind of error, I propose a new language construct that I
>> call a "unit type". It would have the following properties:
>> (1) A definition that would look (very roughly) like this:
>> ```
>> type unit Time as Float
>> = Second
>> | Millisecond == Second 0.0001
>> | Nanosecond == Millisecond 0.0001
>> | Minute == Second 60
>> | Hour == Minute 60
>> | Day == Hour 24
>> | Year == Day 365
>> ```
>>
>> The point of the definition is to:
>> (a) Provide an easy way to define different units that measure the same
>> thing (in this case, time, but you could do the same thing for
>> length/height/depth in either metric or US imperial units) as constructors.
>> (b) Tell how they are related to eachother. (A minute is 60 seconds, an
>> hour is 60 minutes, etc.) The compiler would check that all relations of
>> the constructors eventually flow to a single base unit (in this case,
>> `Second`). A cycle would be disallowed.
>> (c) Tell what type the unit is based on (in this case, `Float`). (Perhaps
>> non-number types would be disallowed.)
>>
>> (2) Given that `every` still has the same signature: `Time -> (Time ->
>> msg) -> Sub msg`, `every 5 toMsg` would cause a compile-time error, because
>> the types don't match; The function expects a number with a `Time` unit,
>> but receives `5`, which is just a raw number (a number without any unit).
>> (3) When writing a function that has a parameter of type `Time`, pattern
>> matching only matches the base unit constructor, not every constructor like
>> a normal (data/enum) type. The compiler would automatically convert the
>> other units to the base unit with the conversions that the programmer
>> provided in the definition.
>> (4) Comparison, addition, and subtraction would be automatically
>> implemented for the type, so two times of any combination of constructors
>> could be compared, added, or subtracted with ease. `(Minute 5) - (Second
>> 20) == (Millisecond 280000)` would "just work". "Time + Float" (or "Time +
>> Length") would cause a compile-time error.
>> (5) Perhaps compound unit types like "Time^2" would be supported, so a
>> "Time * Time" would yield "Time^2", "Time * Float" would yield "Time", and
>> "Time * Length" would yield just that: "Time * Length". ("Force" would be
>> an alias of "Mass * Length / (Second^2)".)
>>
>> I know that this is a very radical proposal, (I don't know of any
>> language that has a feature like this.) but I bring it up anyways, because
>> although it's been 18 years since the mars probe crashed because of a unit
>> error (one module assumed that the number it was getting was in metric
>> units, and another assumed that it was getting it in US imperial units) (
>> https://en.wikipedia.org/wiki/Mars_Climate_Orbiter ), I'm amazed that
>> since then, programming languages have done nothing to prevent this kind of
>> error from happening again, besides just admonishing programmers to be
>> careful. (As if the NASA programmers at the time weren't already trying to!)
>>
>> Letting `5` be a legal unitless `Time` value is just as silly and
>> dangerous as letting `bool a = 2;` be a legal statement in C. data/enum
>> types prevent this from happening to `Bool` in Elm, and unit types could
>> prevent the same kind of thing from happening to `Time`.
>>
>> Questions, comments, related thoughts, etc are welcome.
>>
>>
--
You received this message because you are subscribed to the Google Groups "Elm
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.