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

Tail-recursive replicateA #4234

Merged
merged 2 commits into from
Jun 13, 2022
Merged

Conversation

armanbilge
Copy link
Member

Yet another follow-up :) see #4233 (comment).

It doesn't seem more complex to me than the recursive implementation since it's the same basic algorithm, but I don't feel that strongly. Maybe a benchmark could make it more interesting.


map(loop(n))(_.toList)
map(loop(one, n, pure(Chain.empty)))(_.toList)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a minor anxiety about the extra cost of the map2(a, pure(Chain.empty))(_.concat(_)) being the same as a.

What if we cheat:

      val emptyF = pure(Chain.empty)

      def concat(left: F[Chain[A]], right: F[Chain[A]]): F[Chain[A]] =
        if (right eq emptyF) left else map2(left, right)(_.concat(_))

      @tailrec def loop(fa: F[Chain[A]], n: Int, acc: F[Chain[A]]): F[Chain[A]] =
         if (n == 1) concat(fa, acc)
         else
           // n >= 2
           // so (n >> 1) >= 1 and we are allowed to call loop
           loop(
             map2(fa, fa)(_.concat(_)),
             n >> 1,
             if ((n & 1) == 1) concat(fa, acc) else acc
           )

So we can leverage the law that concat(a, pure(Chain.empty)) == a

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we wrote it as loop(one, n - 1, one) instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I think that works... but for replicateA_ I think we need to rewrite so that we only entire the loop in the n >= 2 case as we do here.

loop(
productR(fa)(fa),
n >> 1,
if ((n & 1) == 1) productR(acc)(fa) else acc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here about leveraging productR(unit)(a) == a to avoid doing a needless productR(fa)(unit)

@danicheg danicheg merged commit 77fbe02 into typelevel:main Jun 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants