effekt-lang / effekt

A language with lexical effect handlers and lightweight effect polymorphism

Home Page:https://effekt-lang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Captures in function signature

dvdvgt opened this issue · comments

Currently, we differentiate between effects and capabilities. Capabilities in a function's signature are to be seen requirements to the call-site and not the actual effects a function may use. This is different to most other languages featuring algebraic effects, where one can easily identify pure functions just by looking at a functions type. For example

def f(): Unit / {} = ...

does not have any requirements for the caller, that is, there are no effects that need to be handled. However, f may still look like this

def f(): Unit / {} =
    try {
         ...
         l.log(...)
         ...
    } with l: Logging {
         ...
    }

even though one may think it is pure at first glance. For the FFI, we currently have the following valid syntax:

extern effect io
extern {io} alert(): Unit = "alert('hey')"

where we can specify which effects a function uses, not requires. Similarly, I propose also make this syntax available to normal definitions:

{ Logging } def g(): Unit / { Logging } = ...
     |                           |
     captures                effects

Here, g uses the effect Logging (left-hand side curly braces) and requires handling of the Logging effect (right-hand curly braces). For f, one would need to write { Logging } def f(): Unit / {} since it uses the effect Logging but does not require handling of that effect. Using this notation, the user can ensure that a function uses only the specified effects and none other. This also allows the user to directly identify/specifying pure function (un-effectful functions) by writing {} def g .... It should also be possible to just omit it and then everything functions as of right now.

Since the effects that are being used are already tracked, this should not require drastic changes and was already (partly) implemented for an OOPSLA-2022 paper.

I can imagine this to be really useful, since it could be great for explaining Effekt's way of dealing with effects and lifting some confusion about the notation of capabilities in conjunction with pure functions. Since it should be completely optional, it won't get in the way of the user if they should not choose to use it.

As it is perhaps the most common use-case, we could introduce the syntactic sugar pure:

pure def f(...): T    :=    {} def f(...): T / {}