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]]