Hey! Can anyone help me? Is there any way to run s...
# arrow
g
Hey! Can anyone help me? Is there any way to run something like IO in in infinity loop with conditional exit? And if answer is tailRecM(), then can you explain how it works internally? Does it use lazy evaluation, or just build sequence until meet condition, and then run it?
s
Hey @genovich, With
IO
you can simply do something like:
Copy code
fun IO<Int>.loop(n: Int): IO<Int> =
  flatMap { i ->
    if(i == n) this
    else IO { i + 1 }.loop( n) 
  }

IO.just(0).loop(10000)
And you could do the same with
tailRecM
.
Copy code
val n = 10_000
IO.tailRecM(0) { i ->
  IO {
    if(i == n) Right(i)
    else Left(i + 1)
  }
}
Where with
tailRecM
we signal using
Either
if we should continue or not, where
Right
signals we found a final result and don't need to keep recursing. This is all gone with Arrow Fx Coroutines though since with
suspend
we can simply write
tailrec
functions. So this the translation of the first
IO
example to a
suspend
one.
Copy code
suspend tailrec fun loop(prev: Int, n: Int): Int =
  if(prev == n) prev
  else loop(prev + 1, n)

prev(0, 10000)
@raulraja I don't know of a straightforward to rewrite this to
Schedule
unless you introduce some atomic field.
Copy code
val n = 10_000
val count = Atomic(0)
arrow.fx.coroutines.repeat(
  Schedule.forever<Int>() zipRight Schedule.doUntil { i -> i == n }
) {
  count.updateAndGet(Int::inc)
}
g
Is
prev
a part of IO? I don't see that field earlier.
s
Whoops sorry, fixed it in the example. I first wrote it with a parameter, and then updated it to be an extension functions 😅
g
I’m sorry about this, but I need to do the same with rxjava. Do you have any suggestions?
s
`Could you describe your use-case a bit more in detail? Do you want to create an
Observable
from a
Schedule
or do you want to
repeat/retry
an
Observable
based on a
Schedule
?
g
If we assume equivalence between
IO
and
Single
, then I want to implement something like
Single.tailRec()
s
Copy code
fun <A, B> tailRecM(a: A, f: (A) -> Single<Either<A, B>>): Single<B> =
      f(a).flatMap {
        when (it) {
          is Either.Left -> tailRecM(it.a, f)
          is Either.Right -> Single.just(it.b)
        }
      }
g
I faced with stackoverflow with this solution
And when I do
f(a).subscribeOn(Schedulers.computation()).flatMap()
then it hangs with about 20000 steps, but whole work were done.
s
Ah yes... RxJava and Reactor don't guarantee stack-safety in their
flatMap
operator..
This is fixable afaik, let me try and whip up a snippet later with stack-safety
What is your use-case? Maybe would be better to write it without
tailRecM
g
Maybe. I’m experimenting with some concepts. One of them is to assume that view is
(T) -> SourceOf<V>
, where
SourceOf<V>
is like
IO
or
Single
. In this case if I want to represent something like
EditText
, I need to do something like
fun loop(initial: String, view: (String) -> SourceOf<String>, endPredicate: (String) -> Boolean): SourceOf<String>
s
Here is a snippet I wrote for Project Reactor on how to make stack-safe. So that should always work for you too.
g
Where?
s
Not sure, if you could fix it using
DeepRecursiveFunction
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-deep-recursive-function/
g
I get it, thank you a lot!
s
Very welcome Vladimir! I'm a bit curious to see what you're building 😄 If you have something to share I'd love to take a look
g
I afraid that you can be disappointed. I’m trying to find answers to some certain questions about software development. Arrow is one of the reasons why I started to do that, and it helps me to find answers.
s
It's a learning process for us all!
g
I can show you something, when I’ll be ready. It feels like I need help with proofs.
👍 1