Skip to content

Atomic effect variables (?) #881

@omegametabroccolo

Description

@omegametabroccolo

Currently this is not possible:

alias eff<x::X,e::E> = <console,x|e>
test.kk(1,33): parse error: invalid syntax
  encountered effect variable x when an effect label was expected
    hint: effect variables must be after `|` (e.g `<labels|e>`), or by themselves (e.g. `e`)

@daanx In your paper describing Koka's effect system, you mention that "An extra restriction [of the type system] is that effect constants cannot be type variables, i.e. αk is illegal", but I didn't understand why this restriction is necessary from the rest of the paper.

I'm asking because I'm writing a library to write choreographies (1, 2, 3) in Koka, which essentially let you write distributed systems as monolitic programs. For example, the two_buyer example from (1) could be written like this:

fun two-buyer()
  val b1/title = b1.locally fn(_) input()
  val s/title = b1.comm(s, b1/title)
  val s/price = s.locally fn(un) catalog.get-price(s/title.un)
  val b1/price = s.comm(b1, s/price)
  val b2/price = s.comm(b2, s/price)
  val b1/contribution = b2.comm(b1, b2-budget)
  val b1/decision = b1.locally fn(un) b1/price <= b1/budget + contribution.un

  // enclave restricts the choreography to b1 and s only
  val b1s/decision = b1.share(s, b1/decision)
  enclave(b1, s) fn(un)

    // This shouldn't typecheck, since b2 isn't part of the sub choreography
    // val b2/dummy = b2.locally fn(_) 42

    if b1s/decision.un then
      val s/delivery = s.locally fn(un) catalog.get-delivery(s/title.un)
      val b1/delivery = s.comm(b1, s/delivery)
      b1.locally fn(un) b1/delivery.un
    else
      b1.locally fn(_) Nothing

I have a choreo effect that provides these operations. Since we want to enforce the census (the set of participants involved in a choreography), the effect should be parametrized over it. With atomic effect variables, we could represent the census with a row:

// A value of type a at location(s) l
type at<a,l::E>
  Local(v: a)
  Remote

// l1 and l2 are phantom types representing single participants (locations). k is a location container, for which we can compute actual values. For the two-buyer example, we could have defined:
//
// struct container<l::X>
//   name: string
//
// type buyer1 :: X
// val b1: container<buyer1> = Container("buyer1")
// ...
//
// choreo itself is private, the commented choreo<...> annotations are exposed by the public interface
alias choreo = <choreo-div<l,k,e>,div|e>
div effect choreo-div<l :: E, k :: X -> V, e :: E>
  // ...
  fun locally(l1: k<l1>, sub: (forall<t> at<t,<l1|_>> -> t) -> choreo<<l1>,k,e> a): /* choreo<<l1|_>,k,e> */ at<a,<l1>>
  fun enclave(l1: k<l1>, l2: k<l2>, sub: (forall<t> at<t,<l1,l2|_>> -> t) -> choreo<<l1,l2>,k,e> a): /* choreo<<l1,l2|_>,k,e> */ at<a,<l1,l2>>
  // ...

In the two-buyer example, enclave would enforce that only b1 and s can be involved in the sub choreography since its census row is closed (doing anything with b2 would be a type error, which is what we want), while the enclave itself is allowed to run within a choreography that involves more participants thanks to its open census row.

My current implementation uses phantom tuples to represent the census instead of phantom rows. I had to overload locally and enclave many times to describe in which contexts they can be used (i.e. a choreo<(l1,l2),...)> enclave is valid inside a choreo<(l2,_,l1),...> context, you can imagine the combinatorial explosion as censuses get bigger), but I just realized that I was just enumerating row extensions / reorderings manually. Maybe there are other solutions I didn't think of, but with atomic effect variables, rows would be a perfect fit.

(I glossed over a lot of details, especially related to choreographic programming, I'm happy to answer questions :))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions