Skip to content

Conversation

@krame505
Copy link
Contributor

@krame505 krame505 commented Dec 8, 2025

Generics can't include arbitrary-kinded type parameters in the generic representation, but we can add any particular kinds. It turns out that we really want to be able to represent constructors of kind * -> * and # -> *. This adds StarConArg and NumConArg to the generic schema, and renames ConArg, the catch-all for other constructor kinds, to OtherConArg. There is a corresponding pull request making this change in bsc-contrib: B-Lang-org/bsc-contrib#39

Change originally by @awpr; I rebased it on the upstream bsc repo and added tests. See MatX-inc#3

@quark17 quark17 force-pushed the lucas/generics-con-args branch 3 times, most recently from aa20a96 to 9aceb66 Compare December 21, 2025 00:48
awpr and others added 5 commits December 21, 2025 16:23
A comment in Prelude observes that higher-kinded args can't be handled
in general; my interpretation is that this is because the lack of
poly-kinded constructors means we can't have a
`ConArg :: (k -> *) -> *`.  But if we really want them, we can have any
particular kind.  I really want these two particular kinds, so I added
them.
@quark17 quark17 force-pushed the lucas/generics-con-args branch from 9aceb66 to c286639 Compare December 21, 2025 03:23
@quark17
Copy link
Collaborator

quark17 commented Dec 21, 2025

What was decided on whether to add a layer of hierarchy that could be matched on as a catch-all? The example in bsc-contrib would seem to illustrate that (1) code will need to be updated when new kinds are added and (2) a separate instance is needed for every kind, even if you don't care about the distinction. A layer of hierarchy would allow one to write a catch-all instance, and it would continue to work if other kinds get added. For example:

data ConArg k = ConArg

data (StarKind :: (* -> *) -> *) i = StarKind
data (NumKind :: (# -> *) -> *) i = NumKind
data OtherKind = OtherKind

(Although I don't know if we need to start worrying about name pollution, and whether some of these types should be made more unique.)

@krame505
Copy link
Contributor Author

I think we decided against another layer of hierarchy, since type classes that want to actually utilize the k in ConArg would then need a catch-all instance for OtherKind, which would still be broken if we added a new kind of constructor.

@quark17
Copy link
Collaborator

quark17 commented Dec 21, 2025

Ok. I also don't think I realized that we already had StarArg, NumArg, and StrArg, and then ConArg. And what I suggested as StarKind and NumKind would actually be something like StarToStarKind and NumToStarKind.

So I can see now that having a catch-all on ConArg now seems ad hoc. One could equally have a layer of hierarchy around all args. Or define layers for different number of kind arrows (one, two, etc). I've not written any generic instances, so I don't have a sense of where one needs these or would want a catch-all. (Is there an example of something that uses even the basic StarArg and NumArg?)

It does make me think StarConArg and NumConArg should be better named -- to StarToStarArg and NumToStarArg -- in case we want to add, say, NumToNumArg, or expand to StarToStarToStarArg. (And maybe OtherConArg becomes OtherKindArg? Or else, name them StarToStarConArg or ConStarToStarArg or similar.)

In fact, maybe this argues for something like this?:

data MetaArg i = MetaArg

data (MetaStarKind :: *  -> *) i = MetaStarKind
data (MetaNumKind :: #  -> *) i = MetaNumKind
data (MetaStrKind :: $  -> *) i = MetaNumKind
data (MetaStarToStarKind :: (* -> *) -> *) i = MetaStarToStarKind
data (MetaNumToStarKind :: (# -> *) -> *) i = MetaNumToStarKind
data MetaOtherKind = MetaOtherKind

which would allow defining an instance for (MetaArg a) that would catch anything that didn't have an explicit instance.

@quark17
Copy link
Collaborator

quark17 commented Dec 21, 2025

Or rather:

data MetaArg a = MetaArg

data (MetaArgStarKind :: *  -> *) i = MetaArgStarKind
data (MetaArgNumKind :: #  -> *) i = MetaArgNumKind
data (MetaArgStrKind :: $  -> *) i = MetaArgNumKind
data (MetaArgStarToStarKind :: (* -> *) -> *) i = MetaArgStarToStarKind
data (MetaArgNumToStarKind :: (# -> *) -> *) i = MetaArgNumToStarKind
data MetaArgOtherKind = MetaArgOtherKind

potentially leaving Kind off, if you want to shorten the names.

@krame505
Copy link
Contributor Author

Hmm, perhaps something like MetaArg could be a bit nicer.

I will note though that we already have a new internal release of bsc and are starting to use it internally, as I thought there was consensus on leaving it as-is at the last meeting. Changing the names again would be a bit annoying on our side and I'm not sure when I'll get around to it. Also, Ravi is on vacation for the next two weeks so I don't think we'll get further input from him soon.

Would you be alright with potentially re-visiting this if we find that we need to support more kinds of type arguments?

@quark17 quark17 merged commit 7884543 into B-Lang-org:main Jan 10, 2026
157 of 158 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants