question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to run two effectful computations at once?

See original GitHub issue

I’m trying to model lazy streams in Effekt. I’ve got an effect representing a push-based producer of values and an effect representing a pull-based consumer of values, but I don’t know how to combine these two things. It seems to require starting two computations and switching between them with resume somehow. Is what I’m trying to do possible? Here’s the code I’ve got so far:

type Option[A] {
  Present(value: A);
  Absent()
}

effect Iterate[A] {
  def yield(element: A): Unit
}

effect Reduce[A] {
  def receive(): Option[A]
}

def inRange(start: Int, end: Int): Unit / Iterate[Int] = {
  do yield(start);
  if (start != end) inRange(start + 1, end);
}

def intoFold[A, S](initState: S) { f: (S, A) => S } : S / Reduce[A] =
  do receive[A]() match {
    case Present(a) => intoFold(f(initState, a)) { (s, a) => f(s, a) }
    case Absent() => initState
  }

def intoSum(): Int / Reduce[Int] = intoFold(0) { (s, a) => s + a }

def reduce[A, B]() { iterator: Unit => Unit / Iterate[A] } { reducer: Unit => B / Reduce[A] } = {
  try {
    reducer();
  } with Reduce[A] {
    def receive() = {
      try {
        iterator();
      } with Iterate[A] {
        def yield(element) = {
          // how to resume the outer reducer?
        }
      }
    }
  }
}

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:8

github_iconTop GitHub Comments

1reaction
jackfirthcommented, Aug 27, 2022

I hit a problem that looks like a bug. In this code:

import immutable/list

type Option[A] {
  Present(value: A)
  Absent()
}

effect Iterate[A] {
  def emit(element: A): Unit
}

effect Reduce[A] {
  def consume(): Option[A]
}

def inRange(start: Int, end: Int): Unit / Iterate[Int] = {
  do emit(start)
  if (start != end) inRange(start + 1, end)
}

def intoList[A](): List[A] / Reduce[A] =
  do consume[A]() match {
    case Absent() => Nil()
    case Present(a) => Cons(a, intoList())
  }

def mapping[A, B] {f: A => B} : Unit / {Reduce[A], Iterate[B]} =
  do consume[A]() match {
    case Absent() => ()
    case Present(a) =>
      do emit(f(a))
      mapping {f}
  }

def reduce[A, B] {iterator: () => Unit / Iterate[A]} {reducer: () => B / Reduce[A]} = {
  var coroutine = fun() {Absent()}
  coroutine = fun() {
    try {
      iterator()
      Absent()
    } with Iterate[A] {
      def emit(e) = {
        coroutine = fun() {resume(())}
        Present(e)
      }
    }
  }
  try {
    reducer()
  } with Reduce[A] {
    def consume() = resume(coroutine())
  }
}

def transduce[A, B, C]
      {iterator: () => Unit / Iterate[A]}
      {transducer: () => Unit / {Reduce[A], Iterate[B]}}
      {reducer: () => C / Reduce[B]}
    : C = {
  reduce[A, C] {iterator} {reduce[B, C] {() => transducer()} {reducer}}
}

def works() = {
  reduce[Int, List[Int]] {inRange(0, 5)} {reduce[Int, List[Int]] {mapping[Int, Int] {x => x * x}} {intoList()}}
}

def fails() = {
  transduce[Int, Int, List[Int]] {inRange(0, 5)} {mapping[Int, Int] {x => x * x}} {intoList()}
}

The works() function works fine, but fails() raises this error at runtime:

TypeError: Reduce$capability_11863.op$consume is not a function

There’s also some strangeness going on where the error isn’t raised every time. I think that’s some goofiness with the in-browser editor though. I haven’t installed Effekt on my machine so I don’t know how much of this is the online editor and how much of this is the Effekt compiler/runtime.

0reactions
jackfirthcommented, Sep 15, 2022

(Ah, I just noticed that I added your code to the tests without asking you 😦 I am sorry; please let me know if I should delete the tests again)

Totally fine with me 😄 Glad I could contribute some useful example code!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Effectful computations in Scala - LinkedIn
Although the approach above is a valid one, it kind of obfuscates the intent to sum 2 values into a third one, as...
Read more >
Stateful Runners of Effectful Computations - ScienceDirect.com
computations should be the same as composing two runs, a run should not only ... Runners are somewhat similar to handlers, but one...
Read more >
Using Python multiprocessing to run object computations
Here's my workaround using queues: from multiprocessing import Process, Queue import time class A: def __init__(self, init): self.a = init ...
Read more >
Parallelism - COS 326: Functional Programming
Below, we will explain how to execute separate computations in separate threads. However, even if your machine has multiple cores, only one core...
Read more >
Effective Programming: Adding an Effect System to OCaml
Type systems designed to track the side-effects of expressions have been around for many years but they have yet to breakthrough into more ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found