Stream: beginners

Topic: Providing Ability Implementation for Type After Declaration


view this post on Zulip batyoullfly (Jul 31 2024 at 00:26):

Is it possible to provide an implementation of an ability for a type after the type has already been declared?

For example, lets say I wanted to create a library for working with polynomials and I wanted to support not only Num *, but also potentially custom numeric types such as imaginary numbers or numbers in a Galois Field for Reed–Solomon codes. Is there any way I could define an ability for arithmetic operations and then make Num * implement this ability so that I could use regular builtin numbers with my functions? Or is there some other way of accomplishing this behavior outside of abilities?

view this post on Zulip Richard Feldman (Jul 31 2024 at 00:31):

so for custom number types specifically (e.g. so that + and such can work on them), it's come up a number of times but there isn't a concrete plan at the moment

view this post on Zulip Richard Feldman (Jul 31 2024 at 00:32):

for the broader question of:

Is it possible to provide an implementation of an ability for a type after the type has already been declared?

in the general case, it's a goal not to support orphan instances for abilities

view this post on Zulip Richard Feldman (Jul 31 2024 at 00:32):

but custom number types is a common recurring request, and it's definitely on the table to include something specific for numbers

view this post on Zulip Richard Feldman (Jul 31 2024 at 00:33):

we just don't have a concrete plan on it right now

view this post on Zulip batyoullfly (Jul 31 2024 at 01:08):

Seems like maybe a custom Arithmetic ability and wrapper functions for a specific type are an okay workaround in the mean time? Not sure if this makes any sense at all

CustomNum.roc

module [
    CustomNum,
    toNum,
    fromNum,
    specialAdd,
    add
]

Arithmetic implements
    add : a, a -> a where a implements Arithmetic

CustomNum a := Num a
    implements [
        Arithmetic {
            add: customNumAdd,
        },
    ]

fromNum : Num a -> CustomNum a
fromNum = \a -> @CustomNum a

toNum : CustomNum a -> Num a
toNum = \@CustomNum a -> a

customNumAdd : CustomNum a, CustomNum a -> CustomNum a
customNumAdd = \@CustomNum a, @CustomNum b -> @CustomNum (Num.add a b)

# imagine some special math stuff
specialAdd : a, a -> a where a implements Arithmetic
specialAdd = \a, b -> add a b |> add b

main.roc

app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br" }

import pf.Stdout
import pf.Task
import CustomNum

specialAddPlainNum : Num a, Num a -> Num a
specialAddPlainNum = \a, b ->
    CustomNum.specialAdd (CustomNum.fromNum a) (CustomNum.fromNum b)
    |> CustomNum.toNum

main =
    specialAddPlainNum 3 5 |> Num.toStr |> Stdout.line!

view this post on Zulip batyoullfly (Jul 31 2024 at 01:09):

Also not really sure how custom abilities work with modules. Seems like I can't have the ability in its own module decoupled from this specific opaque type, and the only way to get the specialAdd function to work in main.roc was to expose add?

view this post on Zulip Brendan Hansknecht (Jul 31 2024 at 01:11):

You can have an ability in it's own module. All ability member functions are just required to be exposed.

view this post on Zulip Brendan Hansknecht (Jul 31 2024 at 01:11):

This is need for the ability to specialize and be possible to implement across module boundaries

view this post on Zulip Brendan Hansknecht (Jul 31 2024 at 01:12):

Then just import the ability and implement it in any other module the same way you implemented it on CustomNum

view this post on Zulip batyoullfly (Jul 31 2024 at 01:21):

Oh okay cool. I might try this approach and see how it works out. For my actual use case of polynomials I don’t need to solve the general case but it definitely feels better to solve the general case. Also might be worth including a snippet of how abilities interact with modules in the abilities page on the website, unless that’s there already and I just missed it

view this post on Zulip Luke Boswell (Jul 31 2024 at 01:25):

If you have any improvements to that Abilities guide, that would be most appreciated! :smiley:

view this post on Zulip batyoullfly (Jul 31 2024 at 01:35):

I don’t feel very qualified but if I get a better hang of how they work maybe I’ll take a stab at it :laughing:

view this post on Zulip Luke Boswell (Jul 31 2024 at 01:38):

My guess is, your about as qualified as I was when I wrote that guide (probably more since you've made something with an Ability) :sweat_smile:

view this post on Zulip Luke Boswell (Jul 31 2024 at 01:38):

I had to scratch around to find the syntax that worked, and then made that guide so I wouldn't forget it (or at least know where to look it up).

view this post on Zulip batyoullfly (Jul 31 2024 at 01:45):

Haha fair enough

view this post on Zulip batyoullfly (Aug 01 2024 at 00:43):

Seems another thing missing from the guide is how to specify a type variable should implement multiple abilities. Had to omit a type signature and see what the language server inferred to see that it was &


Last updated: Jul 06 2025 at 12:14 UTC