Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Jan 31 16:41
    etorreborre closed #162
  • Jan 31 16:41
    etorreborre commented #162
  • Jan 31 14:33
    vitold commented #162
  • Jan 30 22:34
    benhutchison commented #162
  • Jan 30 14:53
    vitold opened #162
  • Jan 26 23:38
    robertbutacu starred atnos-org/eff
  • Jan 23 09:30
    Navneet-gupta01 starred atnos-org/eff
  • Dec 27 2018 04:31
    jugalps starred atnos-org/eff
  • Dec 26 2018 16:07

    etorreborre on master

    Simpler implementation of appli… (compare)

  • Dec 26 2018 16:07
    etorreborre closed #161
  • Dec 26 2018 16:07
    etorreborre commented #161
  • Dec 24 2018 12:36
    kencyke starred atnos-org/eff
  • Dec 24 2018 05:18
    buzden synchronize #161
  • Dec 24 2018 02:36
    TakashiOshikawa starred atnos-org/eff
  • Dec 23 2018 13:59
    crossroad0201 starred atnos-org/eff
  • Dec 23 2018 08:17
    Nymphium starred atnos-org/eff
  • Dec 21 2018 15:05
    buzden synchronize #161
  • Dec 21 2018 14:28
    mflis starred atnos-org/eff
  • Dec 21 2018 11:58
    buzden synchronize #161
  • Dec 21 2018 06:00
    wangpengwen starred atnos-org/eff
Eric Torreborre
@etorreborre

@dispalt I have a rather strong opinion on the subject now. I would not use effects to organise a code base in the sense of having a DatabaseEffect, S3Effect, AuthenticationEffect and so on. I think it is better to use regular case classes, traits (for interfaces - no implementation) and a “wiring” library for this. My latest take on the subject is in Haskell: https://github.com/etorreborre/registry but I think the same idea can be applied to Scala (my previous idea on this: https://github.com/zalando/grafter)

Then the signatures of those components can be parametrized by a monad M which is specified at wiring time. Here you have different choices:

  1. IO for maximum interoperability between the components (because it means “anything can happen”)
  2. ZIO where you can have some guarantees about the kind of errors which can occur
  3. a monad transformer or some MTL constraints. This is unavoidable if you need to pass something like a RequestId across the calls of your whole application and then you need something like a MonadReader RequestId
  4. an Eff r stack which you can think of as an “extensible" monad transformer stack

In any case the monad you use needs to be more or less isomorphic to ReaderT r (IO (Either e)) but nothing more. If you add more “effects” to your monad Mit will be very difficult to use concurrency primitives or bracketing operations (at least in Haskell, in Scala the Eff library has some machinery to support this but at the expense of lots of internal complexity).

In my own work, the only large Scala application I created with Eff is using grafter for wiring and has effects like Task, FlowId, Error, Log and that’s all (Log actually should be a component not an effect).

I think that with this kind of set-up we get the best:

  • modularity
  • encapsulation
  • mocking
  • interoperability of components
  • ease of creation of a subset of the application
  • application lifecycle, with a clean assemble/start-up/run/shutdown separation
Dan Di Spaltro
@dispalt
@etorreborre I've read this a bunch of times, so thank you. I agree, I stopped doing the infrastructure style effects long ago, as it was too cumbersome. I definitely use eff as more of a MTL style.
I still kinda want to see some actual code in the wild doing something more complex than a simple toy app.
Ben Hutchison
@benhutchison

@etorreborre What do you mean by "Log actually should be a component not an effect", can you expand upon this?

Re the number of useful effects, I agree it seems to plateau; Error, Reader, Task are the usual suspects.

I use State effects myself, but I guess that depends if you're updating stateful memory-based system, or its a stateless system that sends all state to an external datastore. Also, I've externalized random RNG via a second orthogonal state effect at times and been happy with the outcome.

Logging via a Writer still seems to make conceptual sense to me.

Ive always used a monolithic IO effect to date, but Im sympathetic to the argument "if you believe in type-safety, shouldn't that apply to IO effect types too?"

When Ive tried the Cats built-in MTL features (after already being Eff fluent), it's seem about as cumbersome to do the same thing, but slightly less flexible
Binzi Cao
@caobinzi

I’ve been playing with tagless final and eff at the same time. I’m still investigating when I should just use tagless final or just eff. I also found eff is much more powerful than tagless when dealing with different effects, because I can use eff to handle multiple effects and I can even wrap an effect with another effect automatically. Some sample code I have tried to use both tagless and eff is as below:

def program[
      F1[_]: FlatMap, //Tagless effect 1
      F2[_]: FlatMap, //Tagless effect 2
      F3[_]: FlatMap, //Tagless effect 3
      R:     MemberIn[LogOp, ?]: MemberIn[Option, ?]: MemberIn[F1, ?]: MemberIn[F2, ?]: MemberIn[F3, ?]
  ](
      gdpr:    GdprOp[F1],
      user:    UserOp[F2],
      console: ConsoleOp[F3]
  ): Eff[R, Unit]

But I’m still not sure if I should just choose one instead of mixing eff and tagless final. any thoughts?

Ben Hutchison
@benhutchison

I dont use tagless final myself but from a casual glance it looks like double abstraction/indirection to me.

My heuristic is to use the simplest solution that works, only take on extra complexity when you know you need it. I did FP without monad stacks for several years, only moved to MTL/Eff when I noticed the complexity ended up higher without monads in a large codebase, eg symptoms: implicit context passing, nested for expressions.

Binzi Cao
@caobinzi
@benhutchison Agree! I found we have so many good libraries in FP now, but it seems we need some FP design rules or how to orginize a real project with FP properly.
Dan Di Spaltro
@dispalt
yeah I like that idea
someone did a good pet store in fp example
I kinda like how @etorreborre thinks about this stuff so I'd love to see a bigger section of a full program to reverse some knowledge from it =)
Eric Torreborre
@etorreborre

@benhutchison you can leave Log as an effect but you don’t have to. Advantages: the Log effect can manage its own environment and be similar to a ReaderT RequestId m ()to log requests with their id. Disadvantage: you cannot wire some logging behaviour for one part of your app and another behaviour for another part (not sure if that’s really needed anyway). Note that if you have Log as a component that does not make your whole stack infected with IO. You can defined the Log component as

data Logger m = Logger {
  info :: Text -> m ()
, error :: Text -> m ()
}

And have your app instantiated in IO while your test code is instantiated with WriterT IO and you use the Writer instance to collect the logs.

Artur Gajowy
@ArturGajowy

Hi! First of all, thank you for this project - I'm very excited to start using it!

I'm considering migrating from cats-mtl transformers to eff, because abstracting over the 5-level stack I have is really hard with mtl typeclasses. My question would be: how does eff compare in terms of performance to 1. mtl transformers, 2. a fused mtl stack used via typeclasses (assuming for a while it's feasible to remain sane after seeing the resulting signatures)?

Artur Gajowy
@ArturGajowy
Also, how hard would it be to provide an effect equivalent to the below StreamT monad transformer?
final case class StreamT[F[_], A](value: F[Stream[A]]) {
  def ap[B](f: F[A => B])(implicit F: Monad[F]): StreamT[F, B] =
    StreamT(F.flatMap(f)(ff => F.map(value)((stream: Stream[A]) => stream.map(ff))))

  def map[B](f: A => B)(implicit F: Functor[F]): StreamT[F, B] =
    StreamT(F.map(value)(_.map(f)))

  def flatMap[B](f: A => StreamT[F, B])(implicit F: Monad[F]): StreamT[F, B] =
    flatMapF(a => f(a).value)

  def flatMapF[B](f: A => F[Stream[B]])(implicit F: Monad[F]): StreamT[F, B] =
    StreamT(Monad[F].flatMap(value)(astream => astream.flatTraverse(a => f(a))))
}
Eric Torreborre
@etorreborre
Hi @ArturGajowy. I’ve never done any real benchmarks but Eff is not really optimised so I don’t think it will compared favourably in tight loops especially in case 2.
I don’t know the answer to your second question. I think that we have to consider that we have a Streaming effect which can be interleaved with other effects. In that case a “Streaming” effect could be supported by a simple Yield a primitive to return the next element in the stream. However this is likely to be super slow. Most streaming libraries support the idea of “chunking” the data in memory to operate on whole “blocks” at the time. So I would probably turn to one of those libraries
Artur Gajowy
@ArturGajowy
The stream is used for handling non-determinism lazily, so perf is not that big of an issue here
Thx for the answer! I guess I'll give it a try anyway and then try to do some benchmarks
kusamakura
@kusamakura
Hello! I've been enjoying Eff lately, but like others in this channel, I'm running into some organizational concerns. I have an interface that is parameterized on a Monad, tagless-final style. Some methods return Option[A] or ThrowableEither[A], and some eventually rely on a Clock effect. So when I use Eff[R, ?] as the service's Monad, I then have to include the superset stack of effects, which pollutes the methods when calling them. I was thinking that I can have an all-encompassing IO effect as the base stack, and then each method would have its own if necessary... What's the ideal way to go about handling this? X)
Eric Torreborre
@etorreborre
Can you please illustrate the “pollutes the methods” part? And “each method would have its own if necessary?
Ben Hutchison
@benhutchison

@kusamakura I think having to acknowledge all effects used in that call-tree, in the type signature, is a feature not a bug ;)

Note you can extend the stack in particular parts of your program, see eg http://atnos-org.github.io/eff/org.atnos.site.Cookbook.html

kusamakura
@kusamakura

@etorreborre Sorry for the late reply and for the unclear description, but @benhutchison read my intent correctly. It's about choosing between 1) putting all effects of all methods in the interface itself, or 2) putting only necessary effects in the methods themselves. I suppose what I wanted to say was that for choice 1 (which I'm currently using), I have to deal with effects that aren't even in use in some methods. To put it concretely:

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

trait GreetingsRepo[M[_]] {
  def get(id: Long): M[String]
  def create(id: Long, greeting: String): M[Unit]
}

class EffGreetingsRepo[R: _Eval: _Option: _ThrowableEither] extends GreetingsRepo[Eff[R, ?]] {
  private[this] val map = collection.mutable.Map.empty[Long, String]

  def get(id: Long): Eff[R, String] =
    delay(map.get(id)).flatMap(fromOption(_))

  def create(id: Long, greeting: String): Eff[R, Unit] =
    map.get(id) match {
      case Some(_) => left[R, Throwable, Unit](new Throwable("already exists"))
      case _ => delay(map.update(id, greeting)).flatMap(right(_))
    }
}

val repo = new EffGreetingsRepo[Fx.fx3[Eval, Option, ThrowableEither]]

// Option[Either[Throwable, String]], ideally just Option[String]
// I realize that I can also take away the Option effect completely,
// in favor of using `either.optionEither` instead of `option.fromOption`
val doGet = repo.get(1L).runEither[Throwable].runOption.runEval.run

I think I just need to understand more of Eff, but I guess this isn't so bad since dealing with this only happens at the end of the world anyway. In any case, thank you for your continued effort in this project/space. :)

Eric Torreborre
@etorreborre
I think that choice n.1 is generally not that bad but in you example I would probably put _Option in the return type directly, like get(id: Long): Eff[R, Option[String]]
kusamakura
@kusamakura
Thanks for the feedback, @etorreborre. I've settled on something like that as well. I suppose I was too excited to move all effects from the return type into the effects stack :p
kaichao
@kaichaosun
Is the Eff[ConnectionIO] still maintain the transaction provided by doobie?
Eric Torreborre
@etorreborre
@dashengSun Eff[R, A] where ConnectionIO |= R is a program having some ConnectionIO effects which means having a ConnectionIO “program” which itself is a set of instructions requiring a database connection to be executed. This is why when you run that effect with runConnectionIO you need to pass a Transactor which contains that connection to the database (actually a connection from a pool of connections)
Dan Di Spaltro
@dispalt
Pushed a pr to support Monix 3.0.0-RC2, let me know what you think.
Dan Di Spaltro
@dispalt
@etorreborre any chance you are going to cut a new eff release soon?
Eric Torreborre
@etorreborre
Dan Di Spaltro
@dispalt
@etorreborre thanks!
Flavio W. Brasil
@fwbrasil
Hi folks! I'm working on an effect mechanism similar to Eff called Lst. I've heard that Eff has some usability issues and was wondering if this new approach addresses them. The main differences from Eff are that Lst preserves the order in which the effects are applied and doesn't use interpreters so it has less boilerplate and probably better performance. I'd love to hear your thoughts on it: https://scastie.scala-lang.org/redHVonuQHy3P3l0Og7WMA
Eric Torreborre
@etorreborre
Hi @fwbrasil! In my experience it is actually important to be able to interpret effects in any order. My current project at work is using freer where the order is constrained and that leads to refactoring issues because an interpreter for a given effect imposes a constraint on where the effect shoud live in the stack of effects. But you say you don’t use interpreters! Doesn’t that defeats the point of effects where we want to have an “abstract language” and then provide different implementations? The other thing that Eff supports is “extensible effects” meaning that a given expression using some effects can be embedded in another expression using more effects. And this is quite important to compose programs without having to know the whole context of the application. This leads to quite a lot of complexity in Eff, I agree, and this is why I have been stepping away from effects recently. I still find effects interesting though :-). I am in the process of translating Sandy Mac Guire’s example with simple records-of-functions and it is interesting to see that this cannot be done with simple modules! The reason is that he is using a “generator” effect which in a way can only be interpreted globally, once you have the full program. However in that case I would rather use a streaming library in my code because this is effectively what we want to do in his example.
In a way we lose the ideal program he describes at the beginning, in another way his ideal program is effectively a series of stream transformations where we want to abstract some of the steps (where the inputs come from, how to process them, how to output them). Once we can use a stream data structure, we can still abstract over all these components without using effects. Anyway that’s probably not very understandable at this stage but I hope to put this in a blog post soon :-)
Ben Hutchison
@benhutchison

Hi @etorreborre Im wondering if you ever tried compiling Eff code with the Dotty compiler?

Dotty is supposed to support the semantics of implicits in Scala 2, but Im finding that Eff code that compiles OK in Scala 2 doesn't compile under dotty.

Perhaps predictably, the problem seems in the interpretation, when the Eff machinery has to strip off effects from the stack, eg runReader. That's powered by that giant implicit "rube-goldberg machine" and perhaps some minor deviation in semantics between the two compilers has thrown it out..

Thinking to make a pair of Scasties, one scala 2.12 & working, same code in dotty failing...

Ben Hutchison
@benhutchison
Eric Torreborre
@etorreborre
@benhutchison no I haven’t tried Dotty and the original set of rules for implicit member resolution were largely experimental. One thing which would be worth trying with Dotty would be to simplify the structure of the Union of effects to come back to a simple list instead of a Tree. The tree structure was adopted because the implicit resolution compilation times were really bad with around 10 effects in the stack. Maybe this has improved?
Eric Torreborre
@etorreborre
Also Member1 is indeed the implicit which should be found but the effect type is inferred to be Nothing instead of `Reader[String, ?]. It would be worth trying to see if you can reproduce this on a very small example
Ben Hutchison
@benhutchison
So there was a bug in Dotty which is now fixed. I'll keep testing Eff with Dotty and report back my experiences..
Eric Torreborre
@etorreborre
Nice!
Jugal Shah
@jugalps
Hello everyone! I have newbie question. I have a program that returns and Eff[ProgramStack, Double].
I was just wondering if there is a way to chain the effects similar to Option.orElse behavior so that
I can replace with another Eff[ProgramStack, Double].
Jugal Shah
@jugalps
When I try to use orElse on the returned Eff[ProgramStack, Double], I get the following error:
No instance found for Member[org.atnos.eff.ErrorEffect.ErrorOrOk, ProgramStack].
The effect org.atnos.eff.ErrorEffect.ErrorOrOk is not part of the stack DealSizeTransformer.this.DealSizeStack
or it was not possible to determine the stack that would result from removing org.atnos.eff.ErrorEffect.ErrorOrOk
Ben Hutchison
@benhutchison

@jugalps late breaking reply...

orElse relates to the meaning of Option. In general, an Eff-expression has no pre-existing meaning, only the meaning you set by the type of ProgramStack. Thats why orElse can't be offered for a just any arbitrary Eff-expr.

Ben Hutchison
@benhutchison
If you want help to try to resolve that error :point_up: , I'd suggest creating a reproducible scastie to share
Eric Torreborre
@etorreborre
@/all I am thinking of donating this project to anyone who has enough skin in the game to be motivated to maintain it, probably the people at REA. I am not using Eff anymore and not even programming much in Scala these days so it might make more sense for someone else to take the lead on maintaining it. Note that @xuwei-k has been super nice in sending lots of small PRs to keep the project up to date but maybe someone wants to take it further in terms of updates and integrations. I will still be around of course to do my best to explain the various corner cases. A migration to Dotty would be super interesting by the way. The various effects of a stack are currently kept in a type-level tree because a type-level list was too slow in terms of compilation times after 6 or seven effects. But that makes the implicits for the Member typeclass a lot more complex than necessary. So it would be cool to see if this has improved with Dotty and the new implicit rules + implementation.
Ben Hutchison
@benhutchison

Hi @etorreborre ,

Im still using Eff and would be willing to take the lead to maintain it. I envisage a basic level of maintenance, keeping releases flowing and eventually migrating to dotty, rather than any major new initiatives. Some extensions might get deprecated if they dont have active user communities

I continue to see value in Effectful FP, and Eff is a very nice solution for that. To me, the challenge to Eff is whether other approaches (eg Cats MTL ) are a simpler way to achieve comparable benefits.

(apologies for the slow reply, I havent been checking Gitter frequently and when I do it usually to seek help with a question.)

Eric Torreborre
@etorreborre

I knew you would step up @benhutchison! I realize that you already are an admin on the project so the only thing left to me is to make an official announcement and whatever else you need from me (for publishing you will need to create an account on oss.sonatype.org and I can create an issue to give you access to the org.atnos group at issues.sonatype.org).

To me, the challenge to Eff is whether other approaches (eg Cats MTL ) are a simpler way to achieve comparable benefits.

This is an excellent remark and I am leaning towards that conclusion: https://medium.com/barely-functional/do-we-need-effects-to-get-abstraction-7d5dc0edfbef. In Haskell-land I see people doubling up on effect libraries (https://github.com/fused-effects/fused-effects, https://github.com/polysemy-research/polysemy). While those libraries are impressive I think the cases where they would bring a competitive advantage are very few. In the end I managed to recover one cool feature of effect libraries which is the ability to compose / recompose interpreters by using my own DI library (https://github.com/etorreborre/registry).

(apologies for the slow reply, I havent been checking Gitter frequently and when I do it usually to seek help with a question.)

You can set email notifications, I just realized that recently :-)

BTW I am still at your disposal if you get lost in the somewhat convoluted implementation of Eff :-)
Ben Hutchison
@benhutchison

Hi Eric, thanks for your confidence in me, much appreciated :)

If you could give me a day or so to review the repo, release process and collect any questions I have around routine maintenance tasks, I'll get back to you.

As a maintainer, my goals will be primarily to issue releases against scala and library releases, review PRs and to investigate bug reports, so existing users of Eff (like REA) can proceed with confidence. Probably little new features from here on.

As mentioned in atnos-org/eff#184, I'll probably look to limit the set of supported integrations (eg Doobie, ZIO etc), and encourage future integrators to self-publish, offering a list of links in README.

Yes, I'll probably tap your knowledge and skills from time to time if I get stuck.

Ben Hutchison
@benhutchison

If you use Eff AddOn integrations with Twitter, Scalaz, Monix or Doobie, please register your use case at atnos-org/eff#186

Im reviewing which AddOns are supported, and understanding the user base for each is key.

tanaka takaya
@takayahilton
Scala 2.13 support