Git Product home page Git Product logo

eff's Introduction

eff

Join the chat at https://gitter.im/atnos-org/eff Maven Central

Extensible effects are an alternative to monad transformers for computing with effects in a functional way. This library is based on the "free-er" monad and extensible effects described in Oleg Kiselyov in Freer monads, more extensible effects.

You can learn more in the User Guide:

You can also check out this presentation at flatMap Oslo 2016 (slides).

Installation

Eff is published for Scala 2.12, 2.13 and 3. eff core is available for the JVM, ScalaJS and scala-native. Sbt dependency:

// check maven badge above for latest version
libraryDependencies += "org.atnos" %% "eff" % "7.0.1"

// to write types like Reader[String, *]
libraryDependencies ++= {
  if (scalaBinaryVersion.value == "3") {
    Nil
  } else {
    Seq(compilerPlugin("org.typelevel" %% "kind-projector" % "0.13.3" cross CrossVersion.full))
  }
}

scalacOptions ++= {
  if (scalaBinaryVersion.value == "3") {
    Seq("-Ykind-projector")
  } else {
    Nil
  }
}

// to get types like Reader[String, *] (with more than one type parameter) correctly inferred for scala 2.12.x
scalacOptions ++= {
  if (scalaBinaryVersion.value == "2.12") {
    Seq("-Ypartial-unification")
  } else {
    Nil
  }
}

Contributing

eff is a Typelevel project. This means we embrace pure, typeful, functional programming, and provide a safe and friendly environment for teaching, learning, and contributing as described in the Scala Code of Conduct.

Feel free to open an issue if you notice a bug, have an idea for a feature, or have a question about the code. Pull requests are also gladly accepted.

Extensions

Modules in this repository

External

  • eff-zio eff extension for ZIO effects.

eff's People

Contributors

a-shkarupin avatar benhutchison avatar buzden avatar crispywalrus avatar dependabot[bot] avatar dvic avatar dyk avatar edmundnoble avatar etorreborre avatar exoego avatar ikempf avatar jarreds avatar jozic avatar n4to4 avatar pavbiz avatar pjan avatar richardimaoka avatar scala-steward avatar scala-steward-bot avatar sh0hei avatar stephanh avatar takayahilton avatar taojang avatar unisay avatar vitold avatar wjlow avatar xuwei-k avatar y-yu avatar youta32449999 avatar zaneli avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eff's Issues

XorT example

I am trying to do

XorT.pure(eff)

where

eff: Eff[SomeEffect, Validated[E, A]]

and I get the following errors:

[error]  both value listInstance in trait ListInstances of type => cats.Traverse[List] with cats.MonadCombine[List] with cats.CoflatMap[List]
[error]  and value optionInstance in trait OptionInstances of type => cats.Traverse[Option] with cats.MonadCombine[Option] with cats.CoflatMap[Option] with cats.Alternative[Option]
[error]  match expected type cats.Applicative[F]
[error]     XorT.pure(s)

This is very weird since my Eff type has nothing to do with Option nor List. Weirdly if I do this:

XorT.pure(s)(optionInstance)

it compiles

Eval does not provide stack-safety (Eval.defer)

Eval is only used in eff-cats for abstraction over evaluation, and there is no mention of trampolining a computation inside Eff[R, A] for R |= Eval. This is because there is no equivalent in EvalCreation to Eval.defer in cats.Eval.

Edit: If this is done, I also recommend adding a comment to runEval indicating that it does not preserve stack-safety.ย 

Translation between State & Reader effect doesnt seem to work anymore

Some background: back in June I asked if it were possible to weaken a State effect down to a Reader, for pieces of code that only read some state, but do not write it back. IIRC @etorreborre showed me a technique on eff-cats gitter, which I started using a version of. Its requires extending the stack with a new Reader effect , which is syntactically a bit clumsy it did meet the goal.

Since the 2.0 upgrade I cant get it to work, when there are other effects that need be in the stack. The prepend operation seems to hide the other effects in some way. The gist below is an attempt to simplify down a reproducible case of the problem Im hitting.

https://gist.github.com/benhutchison/b5d8267a764a22ca893af078ba3a3a27

Value withFilter is not a member of Eff

Becasue withFilter is apparently not a member of Eff, you can not do pattern matching from the monadic flow syntax.

scala> import org.atnos.eff._
import org.atnos.eff._

scala> import org.atnos.eff.all._
import org.atnos.eff.all._

scala> import org.atnos.eff.syntax.all._
import org.atnos.eff.syntax.all._

scala> def f[R](x: (String, String)): Eff[R, String] = for { (a, b) <- pure(x) } yield a + b
<console>:23: error: value withFilter is not a member of org.atnos.eff.Eff[R,(String, String)]
       def f[R](x: (String, String)): Eff[R, String] = for { (a, b) <- pure(x) } yield a + b
                                                                           ^
<console>:23: error: type mismatch;
 found   : Any
 required: String
       def f[R](x: (String, String)): Eff[R, String] = for { (a, b) <- pure(x) } yield a + b

scala> def f[R](x: String): Eff[R, String] = for { a: String <- pure(x) } yield a
<console>:23: error: value withFilter is not a member of org.atnos.eff.Eff[R,String]
       def f[R](x: String): Eff[R, String] = for { a: String <- pure(x) } yield a
                                                                    ^

scala> def f[R](x: String): Eff[R, String] = for { a <- pure(x) } yield a
f: [R](x: String)org.atnos.eff.Eff[R,String]

Release 5.2 with monix upgrade

@etorreborre Can you do a 5.2 release in the next few days?

I want to showcase some Eff w Monix 3.0-RC1 features at Melbourne Scala meetup next Tuesday and it'd be nice if the audience can follow along if they want.

sbt-microsites based documentation for eff?

I often struggle with browsing the eff documentation. At the same time, contributing to the documentation is not straightforward.

Any plans on moving to sbt-microsites (which also uses tut)?

Add eff to scala community build

Hi @etorreborre, both myself personally and REA are now building on top of Eff as a trusted platform.

One way we can strengthen the stability off Eff would be to include it in the Scala community build, so we'll know if future scala versions break it.

I work with Seth as Scala Swing module maintainer already, I'd be happy to volunteer as "build maintainer" for an Eff build.

I can send a PR to add Eff, just wanted to checkin with you first..?

Scala.js build

Is it something you consider? I can probably work on a PR due to our need.

Help to convert tutorials to running programs within a project

I am relatively new to Scala (with Java background) and I am teaching myself Functional Programming. I am working my way through your tutorials.

My problem is that I am only able to get them running through the command line REPL. I have been trying to take the (simple) step of inserting each of the tutorials into a file within IntelliJ IDEA so that they print results to the console. My problem is they won't compile without errors, and I don't know why.

For example, taking code from the "Introduction" here is the file I have created:

class Tutorial{

}

object Intro extends App {
  import cats._
  import cats.data._
  import org.atnos.eff._

  type ReaderInt[A] = Reader[Int, A]
  type WriterString[A] = Writer[String, A]

  type Stack = Fx.fx3[WriterString, ReaderInt, Eval]

  import org.atnos.eff.all._
  import org.atnos.eff.syntax.all._

  // useful type aliases showing that the ReaderInt and the WriterString effects are "members" of R
  // note that R could have more effects
  type _readerInt[R]    = ReaderInt |= R
  type _writerString[R] = WriterString |= R


  def program[R: _readerInt : _writerString : _eval]: Eff[R, Int] = for {
  // get the configuration
    n <- ask[R, Int]

    // log the current configuration value
    _ <- tell("the required power is " + n)

    // compute the nth power of 2
    a <- delay(math.pow(2, n.toDouble).toInt)

    // log the result
    _ <- tell("the result is " + a)
  } yield a


  println(program[Stack].runReader(6).runWriter.runEval.run)
}

The compiler error is in the last line: "Cannot resolve symbol 'run'". I have tried many other approaches and structures, and they all give this error, or some other "Cannot resolve..." error.

I have already tried the "clear cache" fix, with restart of IntelliJ IDEA.

Can anyone help?

How to use catchLeft?

Hi,

I have a number of DSLs (which were written using Eff) that all translate to _throwableEither. All of the translation happens during interpretation - the DSLs themselves do not have any dependency on _throwableEither only their interpreters do.

I want to provide a way for users of the DSLs to handle lefts. However, catchLeft doesn't help capturing this. Is there some way to do this without changing the DSLs? It is okay for DSL users to explicitly specify requirement of _ThrowableEither in the effect stack.

Apologies if I am not following protocol its my first post here. Also, I am very new to Eff and Scala.

-vivek

Explain how to set Monix ExecutionModel of a Task containing an Eff-subprogram

Current Eff API allows putting an Eff sub-program into a Monix Task effect:
def taskSuspend[R :_task, A](task: =>Task[Eff[R, A]], timeout: Option[FiniteDuration] = None): Eff[R, A]

But I am unclear how to obtain precise control of "forking" - specifically ExecutionModel - for Eff tasks. Motivation is to allow tasks collections to execute concurrently.

fromTask(Task.unit.asyncBoundary) >> taskDelay(println(s"Im on ${Thread.currentThread}"))

Would like to understand & document how to write an Eff program with an Async Boundary that enables concurrent execution of Eff-subprograms.

It not clear that this is an Eff "framework", versus "Eff ecosystem" issue, but Im entering it here to keep track of this open question.

Can't run example of using Eff

import cats._, data._
import org.atnos.eff._

type ReaderInt[A] = Reader[Int, A]
type WriterString[A] = Writer[String, A]

type Stack = Fx.fx3[WriterString, ReaderInt, Eval]

import org.atnos.eff.all._
import org.atnos.eff.syntax.all._

// useful type aliases showing that the ReaderInt and the WriterString effects are "members" of R
// note that R could have more effects
type _readerInt[R]    = ReaderInt |= R
type _writerString[R] = WriterString |= R

def program[R :_readerInt :_writerString :_eval]: Eff[R, Int] = for {
// get the configuration
  n <- ask[R, Int]

  // log the current configuration value
  _ <- tell("the required power is "+n)

  // compute the nth power of 2
  a <- delay(math.pow(2, n.toDouble).toInt)

  // log the result
  _ <- tell("the result is "+a)
} yield a

// run the action with all the interpreters
// each interpreter running one effect
program[Stack].runReader(6).runWriter.runEval.run

After compilation get:

No instance found for Member[[ฮฒ$0$]cats.data.Kleisli[[A]A,Int,ฮฒ$0$], A$A57.this.Stack].
The effect [ฮฒ$0$]cats.data.Kleisli[[A]A,Int,ฮฒ$0$] is not part of the stack A$A57.this.Stack
 or it was not possible to determine the stack that would result from removing [ฮฒ$0$]cats.data.Kleisli[[A]A,Int,ฮฒ$0$] from A$A57.this.Stack
program[Stack].runReader(6).runWriter.runEval.run;}
                        ^

What i do wrong? I took this example from introduction http://atnos-org.github.io/eff/org.atnos.site.Introduction.html

Provide and document easy to have shorter method signatures

Hi,

I've recently been starting to use eff. And it's amazing, thanks for building this!

However what keeps bugging me is that it leads to fairly long method signatures for monad stacks with many effects

def foo[R : _foo : _bar : _baz : ...](myArg: MyInputType): MyOutputType

Is there an established best practice for defining aliases for long chains of effect context bounds? If so, could you please add that to the documentation?

Thanks!

intermittent failure in EffApplicativeSpec

seen at e.g. https://scala-ci.typesafe.com/view/scala-2.12.x/job/scala-2.12.x-integrate-community-build/3177/

[eff] [info] EffApplicativeSpec
[eff] [error]  x  uses the applicative "sequencing" whereas >> uses the monadic sequencing
[eff] [error]  
[eff] [error]  action1
[eff] [error]  action2
[eff] [error]  - action1
[eff] [error]  + action2
[eff] [error]  - action2
[eff] [error]  + action1 (EffApplicativeSpec.scala:52)
[eff] [info]  This means that *> will discard the left result but can still run 2 actions concurrently
[eff] [info]  + Eff values can be traversed with an applicative instance
[eff] [info]  + Eff.traverseA is stacksafe
[eff] [info]  + Eff.traverseA preserves concurrency
[eff] [info]  + Applicative calls can be optimised by "batching" requests
[eff] [info]  Interleaved applicative calls can be interpreted properly
[eff] [info]    + with no natural interpretation (see release notes for 4.0.2)
[eff] [info]    + with a natural interpretation (see release notes for 4.4.2)
[eff] [info] Total for specification EffApplicativeSpec
[eff] [info] Finished in 360 ms
[eff] [info] 7 examples, 1 failure, 0 error

sbt launch script in repo is outdated

attempting to use it results in

Downloading sbt launcher for 1.1.4:
  From  http://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch/1.1.4/sbt-launch.jar
    To  /Users/tisue/.sbt/launchers/1.1.4/sbt-launch.jar
Download failed. Obtain the jar manually and place it at /Users/tisue/.sbt/launchers/1.1.4/sbt-launch.jar

you could either update to a more recent sbt-extras, or just not have a launch script in the repo at all, most open source Scala projects don't

fromFuture usage

Hey there, I've seen https://github.com/atnos-org/eff/blob/957fe5b514ee4afa6683fb803772234870749bb6/shared/src/main/scala/org/atnos/eff/AsyncFutureInterpreter.scala and I'm trying to figure out how to use fromFuture.

I have a few methods returning Future and I'd like to incorporate them inside my effect.

So, what I have so far is

  val interpreter = {
    import scala.concurrent.ExecutionContext.Implicits.global
    AsyncFutureInterpreter.create
  }
  import interpreter._

  def program[R : _config : _log : _async]: Eff[R, Future[String]] = for {
    config <- ask[R, Config]
    ip <- fromFuture(connect(config))
    _ <- tell(s"Listening on ${config.host}:${config.port}")
  } yield ip

and this compiles.

However, the fromFuture method comes from import interpreter._. So here I'm coupling the interpreter and the effect building.

Is there a way of working with existing futures in without coupling the specific interpreter?

WIP: Law checking & extending IOEffect typeclasses

This issue is to track some experimental hacking Ive been doing around

  • Supporting the ConcurrentEffect typeclass from cats.effect 0.10 in IOEffect. This is a very speculative, "follow-the-types" implementation and I don't feel confident of its correctness or even sanity - any feedback most welcome. There's some gnarly transient mutable state to work around runIOs inablity to thread non-Unit values down the chain, inspired by @etorreborre hint on gitter last Nov

  • Law checking of the Async instance and this new ConcurrentEffect using Discipline. On the laws branch, cats/test now runs law checks. One finding was that the existing Async fails 10 law checks, once around stack safety and nine times around seemingly not suspending thrown Throwables.

The story behind why I got interested in this area is that I will teach a second Eff workshop at Lambdajam this year. I want to update my material and try to teach whatever is contemporary "best-practice" as at 2018, and I think using cats.effect.IO with Eff would be a nice touch.

However that said, Ive already got the IO effect working fine inside Eff stack, so getting these typeclasses law-checked/working is perhaps a bad habit of looking down passing rabbit-holes :P

CC @alexandru

Compiler crashes

eff version: 4.3.0 (also tried on 4.2.0)
scala version: 2.12.1 (tried LBS and TLS, also 2.11.8)
http://scastie.org/30603

  sealed trait TestAlg[A]

  def interp[R, U, A](effect: Eff[R, A])(implicit m: Member.Aux[TestAlg, R, U], c: _task[U]): Eff[U, A] = ???

  type S = Fx.fx2[TimedTask, TestAlg]
  type R = Fx.fx1[TimedTask]

  def prg[R : _task](implicit R: TestAlg |= R): Eff[R, Int] = ???

  val x0: Eff[S, Int] = prg[S]
  interp(x0) // ok
  val x1: Eff[R, Int] = interp(x0) // compiler explosion
[error]   AdaptTypeError - foundType is Erroneous: org.atnos.eff.Member[Product with Serializable,org.atnos.eff.Fx2[Product with Serializable,Product with Serializable]]{type Out = org.atnos.eff.Fx1[<error>]}

does it makes sense to have a `translateKleisli`

Hi!

Does it makes sense to have something like this in the library (transforming a Kleisli into the target effect if it's part of the stack):

  def translateKleisli[T[_], R, U, S, A](e: Eff[R, A], s: S)(
      implicit mx: Member.Aux[Kleisli[T, S, ?], R, U],
      m: T |= U): Eff[U, A] =
    interpret.translate(e) {
      new Translate[Kleisli[T, S, ?], U] {
        override def apply[X](kv: Kleisli[T, S, X]): Eff[U, X] = {
          send[T, U, X](kv.run(s))
        }
      }
    }

I only saw support for Reader (which is Kleisli with Id as an effect) in the library and I wondered if there was a particular reason for this (I thought I'd ask before preparing a PR).

Thanks for the effort by the way, really like this library!

scalameter as a transitive dependency

So while running benchmarks is a good thing overall leaving scalameter as a runtime dependency with it's transitive dependencies isn't quite so good. Scalameter depends on jackson, scalachart, commons-math and on and on. Yes, I can exclude scalameter my dependencies but I really shouldn't have to. Perhaps a slight refactoring to put the benchmarks in their own package is in order.

Name collision on `Scheduler` when `import org.atnos.eff._` + Monix

Raising this as a discussion - there's not a clear cut solution.

monix.execution.Scheduler is a core abstraction in Monix that you find yourself passing around.

Generally I tend to use wildcard imports of Eff because I use Eff heavily and like to get early warning if there's clashes with other libraries I commonly use. I noticed that recently, the Eff package has added Scheduler which collides with Monix.

Eff's own Scheduler type is pretty young, I wonder if there's scope to migrate it to a less collision-prone name?

Fx.append is not commputative

type FMP = Fx.append[MP, Fx.fx2[Error, TimedFuture]] works fine. However, if I do type FMP = Fx.append[Fx.fx2[Error, TimedFuture], MP] I get the following compiler error:

Cannot prove that org.atnos.eff.Eff[org.atnos.eff.FxAppend[org.atnos.eff.Fx1[org.atnos.eff.TimedFuture],org.atnos.eff.NoFx],scala.util.Either[Throwable,Option[A]]] =:= org.atnos.eff.Eff[org.atnos.eff.Fx.fx1[org.atnos.eff.TimedFuture],scala.util.Either[Throwable,Option[A]]].
[error]           .runAsync,
[error]            ^

Async calls with continuations are not memoized correctly with a memo effect

Consider this example for AsyncFutureInterpreterSpec:

def e14 = {
    var invocationsNumber = 0
    val cache = ConcurrentHashMapCache()

    type S = Fx.fx2[Memoized, Async]
    val intAsync: Eff[S, Int] = asyncFork[S, String]("a").flatMap( x => asyncFork[S, Int]({ invocationsNumber += 1; 1 }))
    def makeRequest = asyncMemoized("only once", intAsync)

    (makeRequest >> makeRequest).runAsyncMemo(cache).runAsyncFuture must be_==(1).await
    invocationsNumber must be_==(1)
  }

Looks like flatMapping causes the result of the first async to be cached. I would expect 1 to be cached, however "a" is cached instead:

[error]  x Async calls with continuations can be memoized with a memo effect
[error]  'a' is not equal to '1' (AsyncFutureInterpreterSpec.scala:179)

Who "invented" Eff? Gordon Plotkin and Matija Pretnar afaict...

The introduction to this library might lead people into thinking that Kiselyov etc "invented" Eff, as it did me for a long time. In fact there was an explosion of different implementations of algebraic effects in the 2011 to 2013 timescale. But in my opinion, some credit for Eff should be attributed to Gordon Plotkin and Matija Pretnar whose theoretical work seems to have enabled them all.

Errors interpreting stacks in Eff 2.0 RC7 in ammonite repl

I started out seeing strange order-dependence in a non open source codebase using a Fx.fx6 stack, as others had reported on gitter, for code that IIRC worked fine on 1.7.x. Got it to compile and run by interpreting in this order: Option, State, State, Reader, Writer, Xor.

So I tried to simplify the problem down in an ammonite repl, but saw alot of more basic errors for things that I thought should work: https://gist.github.com/benhutchison/720fcea4e03692bef383b3c05694981a

Traverse instance for Eff

I think we should be able to provide a Traverse instance for Eff[S, A], given that all of the members of S have Traverse instances; by this I mean that all of them are possible to run without detach.

supporting doobie

Would you be interested in having support for Doobie effects (i.e., ConnectionIO)? Or is this out of the scope of the project? I have been playing with this idea and currently have the below interpreter as a proof of concept (requiring as last effect on the task Task). It currently rewrites in terms of monix.eval.Task but this would of course be generalized. The interpreter also handles errors, calling the configured Strategy ConnectionIO programs of the Doobie transactor, which are by default:

  • before (set autoCommit false)
  • after (commit)
  • oops (rollback)
  • always (connection close)
type TaskStack = Fx.fx1[Task]
def runConnectionIO(t: Transactor[Task, HikariDataSource])(
    implicit m1: Member.Aux[ConnectionIO, R, Fx.fx1[Task]]): Eff[TaskStack, A] = {

  for {
    c <- send[Task, TaskStack, Connection](t.connect(t.kernel))
    res <- {

      val eInterpreted: Eff[TaskStack, A] = {
        interpret.translate(e)(new Translate[ConnectionIO, TaskStack] {
          override def apply[X](kv: ConnectionIO[X]): Eff[TaskStack, X] = {
            TaskCreation.fromTask(kv.foldMap(t.interpret).run(c))
          }
        })
      }

      val beforeAfter: Task[A] = for {
        _   <- t.strategy.before.foldMap(t.interpret).run(c)
        res <- eInterpreted.into[TaskStack].runSequential
        _   <- t.strategy.after.foldMap(t.interpret).run(c)
      } yield res

      val always = t.strategy.always.foldMap(t.interpret).run(c)
      val oops   = t.strategy.oops.foldMap(t.interpret).run(c)

      send[Task, TaskStack, A](
        beforeAfter
          .recoverWith({ case err => oops *> Task.raiseError[A](err) })
          .doOnFinish(_ => always)
          .doOnCancel(oops *> always)
      )
    }
  } yield res
}

Provide syntax to lift plain values into Eff?

I have this mixed-in thru a package object:

  implicit class Id[A](val a: A) {
    def pureEff[E]: Eff[E, A] = EffMonad[E].pure(a)
  }

I find it regularly useful, allows type A to be inferred. I chose pureEff rather than pure because of name collision.

Twitter util Future for Async

Along with Scala Future, Scalaz Task and Monix Task I think it would be useful to provide integration (Async effect) with twitter util future. I've just started playing with Eff and I believe that I do not have enough expertise with Eff to implement it myself correctly (at least right now and fast :) ) But I'm ready to take a shot if no one will pick this up in the near future.

Add interpret.augment

Add a way to use a F ~> Union2[Fx.fx2[F, G], ?] to use the info contained in F's structure to add a G effect to an effect stack already containing an F. I'm thinking interpret.augment but that's just an idea.

Unable to get Futures working concurrently

We are unable to get TimedFuture to do any work concurrently after we upgraded from 3.0.4. I have created the reproducible test cases at :-

Despite having enough threads, the futures seems to be executing sequentially after we upgrade from 3.0.4 to 4.0.2. We have attached YourKit thread images in those repos.

Is this is bug or are we using the library wrong in some way?

Another point to note is that the following code where we use TimedFutures directly (rather than being translated into) works fine on 4.2.0 :-

import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

import java.util.concurrent.Executors

import cats.implicits._

import org.atnos.eff._
import org.atnos.eff.Interpret.translate
import org.atnos.eff.future._
import org.atnos.eff.all._
import org.atnos.eff.syntax.all._
import org.atnos.eff.syntax.future._


object Test {
  def q(i: Int, sleep: Long) = for {
    _ <- p(i, 0, sleep)
    _ <- p(i, 1, sleep)
    _ <- p(i, 2, sleep)
  } yield ()

  def p(i: Int, j: Int, sleep: Long) = futureDelay {
    println(s"Starting $i-$j")
    Thread.sleep(sleep)
    println(s"Finished $i-$j")
  }

  type T = Fx.fx1[TimedFuture]
  val x = Eff.traverseA[T, List, Int, Unit](List(1, 2, 3, 4))(i => q(i, 10000))

  def main(args: Array[String]): Unit = {
    implicit val scheduler = ExecutorServices.schedulerFromScheduledExecutorService(Executors.newSingleThreadScheduledExecutor())
    Await.result(
      x.runAsync,
      5 minutes
    )
  }
}

How to use a specific stack

Suppose I have a Stack like

type LogWriter[A] = Writer[LogEntry, A]
type Result[+A] = Either[LogicError, A]
type RequestIdReader[A] = Reader[RequestId, A]

type Stack = Fx.fx4[LogWriter, Async, Result, RequestIdReader]

and some convenience type aliases

type _log[R] = LogWriter |= R
type _async[R] = Async |= R
type _result[R] = Result |= R
type _requestId[R] = RequestIdReader |= R

Now, in some parts of my application I know that I will be working with that specific stack, so for instance instead of

def someMethod[R: _log : _async : _result : _requestId](someParam: Int): Eff[R, Int] = ???

I would like to specify Stack directly. Something like

def someMethod[R: Stack](someParam: Int): Eff[Stack, Int] = ???

Clearly this doesn't work, but I can't figure out a syntax for expressing this.

Is there a concise way to say that multiple effects (all the ones that compose my Stack) are member of a stack?

How to use fs2.Stream compile for Eff[R, ?] ?

Hi Eric,

I'm currently puzzled a bit with understanding the proper usage of both Eff and fs2.Stream API.

What I want to do (let's assume some synthetic situation):

def getEffects[S: _io : _option]: Eff[S, Int] = Eff.pure(1)
type Stack = Fx2[IO, Option]
Stream.eval(getEffect[Stack])
        .compile
        .toList
        .runOption
        .unsafeRunSync

and apparently it fails with

could not find implicit value for parameter compiler: fs2.Stream.Compiler[[x]org.atnos.eff.Eff[Stack,x],G]
[error]     val res: Eff[Stack, List[Int]] = Stream.eval(getEffect[Stack]).compile.toList

According to fs2 documentation, adding the instance of cats.effect.Effect helps, but i have a problem with writing the actual implementation of some functions:

    implicit def effectEff[R]: cats.effect.Effect[Eff[R, ?]] = new cats.effect.Effect[Eff[R, ?]] {
      override def runAsync[A](fa: Eff[R, A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[Unit] = ???

      override def async[A](k: (Either[Throwable, A] => Unit) => Unit): Eff[R, A] = ???

      override def asyncF[A](k: (Either[Throwable, A] => Unit) => Eff[R, Unit]): Eff[R, A] = ???

      override def suspend[A](thunk: => Eff[R, A]): Eff[R, A] = {
        fromIO(IO(thunk)).flatten
      }

      override def bracketCase[A, B](acquire: Eff[R, A])(use: A => Eff[R, B])(release: (A, ExitCase[Throwable]) => Eff[R, Unit]): Eff[R, B] = {
        Eff.bracketLast(acquire)(use)(a => release(a, ExitCase.complete[Throwable]))
      }

      override def flatMap[A, B](fa: Eff[R, A])(f: A => Eff[R, B]): Eff[R, B] = fa.flatMap(f)

      override def tailRecM[A, B](a: A)(f: A => Eff[R, Either[A, B]]): Eff[R, B] =
        Eff.EffMonad[R].tailRecM(a)(f)

      override def raiseError[A](e: Throwable): Eff[R, A] = ???

      override def handleErrorWith[A](fa: Eff[R, A])(f: Throwable => Eff[R, A]): Eff[R, A] =
        ioAttempt(fa).flatMap {
          case Left(t) => f(t)
          case Right(a) => Eff.pure(a)
        }

      override def pure[A](x: A): Eff[R, A] = Eff.pure(x)
    }

Looking into the type signatures now I'm wondering does it even make any sense?

Macro improvements

  1. eff macro should be able to generate smart constructors having no parameter lists. Atm it throws an IndexOutOfBoundsException: 1 at org.atnos.eff.macros.EffMacros$$anonfun$4.applyOrElse(EffMacros.scala:119) when trying to do so.
  2. eff macro should recognize Member and MemberIn type aliases when defined as aliases of |= and <= respectively. Atm it just claims that they are not provided.

Add a catchWrong method similar to catchLeft

Add a catchWrong method to Validate similar to catchLeft in Xor.

The signature could be something like:

catchLeft(r: Eff[R,A], handle: NonEmptyList[E] => Eff[R,A])(implicit m: Validate[E, ?] |= R): Eff[R, A]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.