links-lang / links

Links: Linking Theory to Practice for the Web
http://www.links-lang.org
Other
333 stars 43 forks source link

Effect aliasing #1141

Closed Orbion-J closed 2 years ago

Orbion-J commented 2 years ago

I added the possibility to write effect aliases, similarly as what already exists for types.

About implementation, I copied and then merged most of the time what existed for typename.

jamescheney commented 2 years ago

I don't know the backstory of this, and haven't had a chance to look at this carefully, but instead of adding a keyword and duplicating a lot of code for typename, would it be possible (and wouldn't it be nicer) to augment typename to allow an optional kind, and generalize it to allow any kind of type alias (with Type being the default used if no explicit kind is given)?

e.g. instead of

effectname MyEffectRow(a, ... ,e::Eff, ...) = { Op1 : type, ... | e }

could we write

typename MyAlias(...) :: K = ty

for any kind K, with Eff being a special case, and just generalize the existing code for aliases to allow this?

The description and comments suggest that this may not be straightforward, because of existing idiosyncrasies, but the above design seems cleaner and something we should work toward (see also #44 and comments about row aliases). Perhaps a constructive compromise could be to adopt this PR with a small change: allowing (in addition or only)

typename  MyEffectRow(a, ... ,e::Eff, ...):: Eff =  { Op1 : type, ... | e }

as a special case without (yet) trying to generalize to allow aliases of any kind.

Orbion-J commented 2 years ago

@jamescheney I can surely do something that looks like that. At least syntacticly, I can check during parsing which kind do we have and use after the same things I ve already done. I will still try see how complicated it would be to extend to presence, in order to be able to at least use it for every primary kind.

dhil commented 2 years ago

I don't know the backstory of this, and haven't had a chance to look at this carefully, but instead of adding a keyword and duplicating a lot of code for typename, would it be possible (and wouldn't it be nicer) to augment typename to allow an optional kind, and generalize it to allow any kind of type alias (with Type being the default used if no explicit kind is given)?

Ultimately, we want to do something like that. But we before we do that we should have a design in mind. The point of this change is to introduce the minimal thing that let us tweak the programming experience / presentation with / of effects and handlers.

In its current state this patch is more invasive than I had originally intended. However, it is probably fine, but we need to be a bit more careful about mixing kind type and row in one alias environment -- I am sure this approach opens up an avenue for a lot of new bugs.

Orbion-J commented 2 years ago

I fixed the simple things. I tried to add what james was suggesting, I had to do a a bit of a hack in the parser to make it work but it seems to be ok. I added also a few things for presence but this is neither complete nor working. Anyway, you are right mixing everything could cause some unexpected behavior as :

links> typename A = Int ;
A = Int
links> effectname B = { Op:() -A-> () } ;
***: Error: File "core/types.ml", line 1435, characters 11-17: Assertion failed 

this should for instance cause a kind mismatch. I think checking in instantiate.ml would help but there could be other issues.

dhil commented 2 years ago

I fixed the simple things. I tried to add what james was suggesting, I had to do a a bit of a hack in the parser to make it work but it seems to be ok. I added also a few things for presence but this is neither complete nor working. Anyway, you are right mixing everything could cause some unexpected behavior as :

links> typename A = Int ;
A = Int
links> effectname B = { Op:() -A-> () } ;
***: Error: File "core/types.ml", line 1435, characters 11-17: Assertion failed 

this should for instance cause a kind mismatch. I think checking in instantiate.ml would help but there could be other issues.

Yes. Do not implement James' suggestion. That's for later when we have worked out a proper design. It is too much to bundle it all up.

jamescheney commented 2 years ago

Do not implement James' suggestion. That's for later when we have worked out a proper design. It is too much to bundle it all up.

Of course, I was just asking if this was a "good enough for now" change or intended as a long-term proper design.

Orbion-J commented 2 years ago

I discussed with Sam today and he suggested to me to add kind information in the alias context. I also added that info to each alias instance, so that we can know easily the kind, without having to compute it. It solves then https://github.com/links-lang/links/pull/1141#discussion_r883741660. For now I just used the primary kind but it could easily be extended to a complete kind if needed.

Within this setting, we can fail when we encounter a situation like in https://github.com/links-lang/links/pull/1141#issuecomment-1139875149 :

links> typename A = Int ;
A = Int
links> effectname E = { X : () -A-> () } ;
<stdin>:1: Kind mismatch: Type argument 0 for type constructor A has kind Type, but an argument of kind Row was expected. 
In:
() -A-> ()

I used the kind mismatch error that already exists. I should probably create a new error because the message is not very appropriate. fixed