Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: add Task.flatMapLoop method #995

Closed
3 tasks
alexandru opened this issue Aug 28, 2019 · 10 comments
Closed
3 tasks

Proposal: add Task.flatMapLoop method #995

alexandru opened this issue Aug 28, 2019 · 10 comments

Comments

@alexandru
Copy link
Member

alexandru commented Aug 28, 2019

I think this method would be cool to have on Task:

sealed abstract class Task[+A] {

  // ...

  def flatMapLoop[S](seed: S)(f: (A, S, S => Task[S]) => Task[S]): Task[S] =
    this.flatMap { a => f(a, seed, loop(_)(f)) }
}

Usage sample:

val random = Task(Random.nextInt())

random.flatMapLoop(Vector.empty[Int]) { (a, list, continue) =>
  val newList = list :+ a

  if (newList.length < 10)
    continue(newList)
  else
    Task.now(newList)
}

This saves us from describing a loop via def, which I find super annoying:

def loop(list: Vector[Int]): Task[Vector[Int]] =
  random.flatMap { a =>
    val newList = list :+ a

    if (newList.length < 10)
      loop(newList)
    else
      Task.now(newList)    
  }

loop(Vector.empty)

So it's a syntactic helper that's similar with onErrorRestartLoop.


TODO:

  • check if there's already an alternative in Cats (when in doubt, ask on Cats's gitter :))
  • get the signature right, one problem is that this looks like a foldLeft, however usually the order of params in foldLeft in Scala is (S, A) and not (A, S) (like we're doing here)
  • also add it for Coeval
@alexandru
Copy link
Member Author

Btw, this helper is super obvious — is it described anywhere? In Cats maybe?

@mudsam
Copy link
Contributor

mudsam commented Aug 28, 2019

I can take a stab at it if you want.

@alexandru
Copy link
Member Author

👍 let's call it flatMapLoop, has a nicer ring to it. Also search for an equivalent in Cats first.

@alexandru alexandru changed the title Proposal: add Task.collectLoop method Proposal: add Task.flatMapLoop method Aug 29, 2019
@alexandru
Copy link
Member Author

alexandru commented Aug 29, 2019

One issue we need to solve is to get the signature right — this function looks like a foldLeft:

def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B

This is consistent with the definition from Haskell:

foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b

In other words maybe the signature should be:

def flatMapLoop[S](seed: S)(f: (S, A, S => Task[S]) => Task[S]): Task[S]

On the other hand we have the problem that we already described:

def onErrorRestartLoop[S, B >: A](initial: S)(f: (Throwable, S, S => Task[B]) => Task[B]): Task[B]

This would be a problem. And I think we might have gotten this signature wrong.

@alexandru
Copy link
Member Author

Note that foldRight on the other hand is:

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B]

So maybe this is more like a foldRight 😂

@mudsam
Copy link
Contributor

mudsam commented Sep 4, 2019

PR coming tonight (US Mountain Time). I was not able to find a similar method in cats. Currently working on a couple of test cases. Regarding the signature do you want to keep it as is or change it?

@alexandru
Copy link
Member Author

Consistency with onErrorRestartLoop is important, so unless I hear objections, then we'll keep the signature.

@mudsam
Copy link
Contributor

mudsam commented Sep 5, 2019

Will be delayed til tomorrow

@mudsam
Copy link
Contributor

mudsam commented Oct 3, 2019

Anything else needed in the PR?

@Avasil
Copy link
Collaborator

Avasil commented Oct 22, 2019

Thank you for the PR @mudsam and sorry for the delay!

@Avasil Avasil closed this as completed Oct 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants