Heyyo, I was looking at how elm-units manages to make a type safe way to do units of measure stuff, but I've never done any Elm, so I'm having trouble converting it to Roc.
I've simplified down elm-units by removing all the type aliases and renaming the types and tags to have distinct names and confirmed that it still typechecks as you'd expect, i.e. you can add metres and feet but not metres and kilograms.
type TypeQuantity number units = TagQuantity number
type TypeMeters = TagMeters
type TypeKilograms = TagKilograms
meters : Float -> TypeQuantity Float TypeMeters
meters numMeters = TagQuantity numMeters
feet : Float -> TypeQuantity Float TypeMeters
feet numFeet = meters (0.3048 * numFeet)
kilograms : Float -> TypeQuantity Float TypeKilograms
kilograms numKilograms = TagQuantity numKilograms
plus : TypeQuantity number units -> TypeQuantity number units -> TypeQuantity number units
plus (TagQuantity a) (TagQuantity b) = TagQuantity (a + b)
heightA = meters 2
heightB = feet 6
weightA = kilograms 100
x = plus heightA heightB -- Type checks
y = plus heightA weightA -- Doesn't type check
Here's my attempt at converting to Roc:
TypeQuantity number units : [TagQuantity number]
TypeMeters : [TagMeters]
TypeKilograms : [TagKilograms]
meters : F64 -> TypeQuantity F64 TypeMeters
meters = \numMeters -> TagQuantity numMeters
feet : F64 -> TypeQuantity F64 TypeMeters
feet = \numFeet -> meters (numFeet * 0.3048)
kilograms : F64 -> TypeQuantity F64 TypeKilograms
kilograms = \numKilograms -> TagQuantity numKilograms
plus : TypeQuantity number units, TypeQuantity number units -> TypeQuantity number units
plus = \TagQuantity x, TagQuantity y -> TagQuantity (x + y)
I think part of the problem is that in Elm the type
keyword creates a new type, but in Roc the :
only creates a type alias, so I tried converting Quantity
to an opaque type, but opaque types can only have one type parameter, so I'm stumped :thinking:
Any help would be great, thank youuuuuu :)
but in Roc the
:
only creates a type alias, so I tried convertingQuantity
to an opaque type, but opaque types can only have one type parameter
They can have many. For example, dict has 2
Oh! Then I've probably misunderstood this error:
MyOpaqueType a b := [MyTag a b]
f : a, b -> MyOpaqueType a b
f = \x, y -> @MyOpaqueType x y
29│ f = \x, y -> @MyOpaqueType x y
^^^^^^^^^^^^^^^^^
Note: Opaque types always wrap exactly one argument!
What is the compiler trying to tell me?
@MyOpaqueType (MyTag x y)
Ah, thank you! Managed to get it to work now!
Here's my code in case someone else finds this thread and was wondering:
Quantity number units := number
Meters := [Meters]
Kilograms := [Kilograms]
meters : F64 -> Quantity F64 Meters
meters = \numMeters -> @Quantity numMeters
feet : F64 -> Quantity F64 Meters
feet = \numFeet -> meters (numFeet * 0.3048)
kilograms : F64 -> Quantity F64 Kilograms
kilograms = \numKilograms -> @Quantity numKilograms
plus : Quantity _ units, Quantity _ units -> Quantity _ units
plus = \@Quantity a, @Quantity b -> @Quantity (a + b)
heightA = meters 2
heightB = feet 6
weightA = kilograms 100
Hannes has marked this topic as resolved.
Last updated: Jul 06 2025 at 12:14 UTC