Stream: beginners

Topic: ✔ Help translating some Elm to Roc


view this post on Zulip Hannes (May 17 2024 at 03:59):

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 :)

view this post on Zulip Brendan Hansknecht (May 17 2024 at 06:03):

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

They can have many. For example, dict has 2

view this post on Zulip Hannes (May 17 2024 at 06:07):

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?

view this post on Zulip Brendan Hansknecht (May 17 2024 at 06:17):

@MyOpaqueType (MyTag x y)

view this post on Zulip Hannes (May 17 2024 at 06:47):

Ah, thank you! Managed to get it to work now!

view this post on Zulip Hannes (May 17 2024 at 06:48):

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

view this post on Zulip Notification Bot (May 17 2024 at 07:48):

Hannes has marked this topic as resolved.


Last updated: Jul 06 2025 at 12:14 UTC