flatMap
effects to make them "happen".flatMap
? Why can't I, say,. map over an fs2.Stream
of effects and have them "executed"? Is the choice of flatMap
arbitrary or are there mathematical laws at play here? If so, what are these laws?
F[A]
map: F[A] => (A => B) => F[B]
cannot execute further effects in the function simply because there are none there
A => F[B]
,which on more fundamental level, it's the general concept of a continuation when you represents effects in this style (programs as values)
Stream
you have evalMap: Stream[F, A] => (A => F[B) => Stream[F, B]
flatMap(a => Stream.eval(f(a))
flatMap
in strict side-effecting languages as well, if you squint
flatMap
@SystemFw I guess as a newbie I don't have the mental model. I've learned by rote that one must flatMap
but I can see why after years of mapping over Scala collections one might naively think this:
val printEffect: Int => IO[Unit] = x => IO { println(x) }
val printEach: Pipe[IO, Int, Unit] = { _.map(x => printEffect(x)) }
printEach(Stream(1, 2, 3, 4, 5)).compile.toList
prints out the numbers 1 to 5.
It is, of course, wrong. But why (other than "it just is") is currenlty eluding me.
Can you please expand on why A => F[B]
is a program and F[A] => (A => B) => F[B]
is not?
B
println
doesn't exist, as you note
println: Unit
purePrintLn: IO[Unit]
map: F[A] => (A => B) => F[B]
F
is Stream
map: Stream[IO, A] => (A => B) => Stream[IO, B]
A
is Int
A => B
unifies with Int => IO[Unit]
Pipe[IO, Int, IO[Unit]]
map
has no idea that what you return is a program
IO
for a minute
map[A, B]: IO[A] => (A => B) => IO[B]
IO
is a datatype, which gets interpreted
map
is fully parametric on A
and B
B
to do special things
B
s, i.e. B = IO[C]
, you want to do something else
ioA.map(printEffect)
, it gets treated as any other B
, i.e. you get IO[IO[Unit]]