Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Fabio Labella
@SystemFw
def + by name is, and in that model val is the equivalent of <-
but the whole thing is then easier to understand by considering IO[A] = () => A , which has the limitations outlined above
(you can replace all def t: A with val t: () => A)
Paul Snively
@paul-snively
Maybe it's worth looking at the implementation of Id, which you might think of as "the fake monad."
Drew Boardman
@drewboardman
Id is a datatype
Paul Snively
@paul-snively
So is IO, and they both have Monad instances.
Among others.
The point is, you can compare what happens in various scenarios in code using Id and in code using IO, and see how they differ (because the latter takes great care to satisfy various laws under a broad range of operational conditions, and the former doesn't).
Fabio Labella
@SystemFw

https://github.com/SystemFw/Scala-World-2019/blob/master/Examples.scala

Here there are a few implementations of IO, the first one of which is essentially with () => A. But I do think that looking at the implementation is not the right way to understand IO at first

which is great, it means we actually have an abstraction
Christopher Davenport
@ChristopherDavenport
I’m missing a lot of context. But Id is by no means a fake monad.
Paul Snively
@paul-snively
Looking at the implementation of IO is a horrible way to understand it, I think.
Vinayak Pathak
@vinayakpathak
@SystemFw nice, that's great. that answers a lot of my questions. I'm probably going to start thinking of IO as () => A until I realize it's a huge simplification
Fabio Labella
@SystemFw
well, I wouldn't recommend that :)
Paul Snively
@paul-snively
@ChristopherDavenport: Sure. I should have put "fake" in scare-quotes, at the very least.
Fabio Labella
@SystemFw
this is a general point about FP btw
trying to start using algebraic thinking
it's actually the biggest benefit imho, one of the ultimate goals
and it's hard to get your head around that at first
switching mindset from executing actions to composing programs
and I think that the earlier you start trying, the better
Paul Snively
@paul-snively
@vinayakpathak: Just to give one example: the () => A model certainly doesn't give you IO(1) |+| IO(1).
Christopher Davenport
@ChristopherDavenport
Or race, or async, or continual. Without even considering +Effect
Or for that matter Bracket
Fabio Labella
@SystemFw
IO[A] is a program. Option[A] is a program. These programs can be composed using certain operations. You build your code by building mini-programs, assembling bigger programs out of small ones, and translating programs from one "language" to another (eg. fs2.Stream to IO, or Option to Either)
Vinayak Pathak
@vinayakpathak
@SystemFw yeah, but with IO you get to write things that look like they are about executing actions but they're really about composing programs... so it's a little confusing
Fabio Labella
@SystemFw
I have a suggestion for that
avoid for
completely avoid it for the time being
Vinayak Pathak
@vinayakpathak
ah interesting
Fabio Labella
@SystemFw
use explicit flatMap and other combinators
for prioritises brevity over clarity, and when trying to form a clear semantic mental model it's unhelpful
Vinayak Pathak
@vinayakpathak
i'm gonna try that
Fabio Labella
@SystemFw
(note that the same ambiguity happens with something as simple as Option as well, but one only starts thinking about it with more powerful types like IO etc.)
but do try that, and do try to forget entirely how things are implemented
(for the time being at least)
you can actually do it with something as simple as Option first
Paul Snively
@paul-snively
Also, avoiding monads is helpful. Then you can't use for.
Fabio Labella
@SystemFw
forget about Option being a datatype made by Some and None, and don't use pattern matching
Vinayak Pathak
@vinayakpathak
you think using pattern matching distracts you from thinking in terms of compositionality as well?
Fabio Labella
@SystemFw
typing a complete example, hold on
Vinayak Pathak
@vinayakpathak
okay!
Christopher Davenport
@ChristopherDavenport
Yeah, it can make you think of Some/None rather than fold whereas in FP its much easier to see them as Option everywhere.
Drew Boardman
@drewboardman
is there any future plan to enforce typeclass coherence in scala?
like in scala 3 or something?
Fabio Labella
@SystemFw

Option[A] is a program. There are two ways of constructing primitive programs in the " Optional language". One is with pure[A](a: A): Option[A], the other is with empty[A]: Option[A]. Then you have ways of composing these Optional programs. map transforms the result of an Option[A] into an Option[B], assuming you can encode this transformation as A => B. But there is an interaction with empty! empty.map(f) = empty. This gives us semantics: optional programs can express short-circuiting. You can have more powerful ways of composing optional programs, for example by building programs that depend on the result of the previous program: Option[A] => (A => Option[B]) => Option[B] , which is flatMap. Flatmap also shorcircuits on empty programs. Another way you can compose optional programs is by choice, by taking a different path when you find an empty program, this is orElse. Finally, when you are done composing, you need to run this program, which is A => Option[A] => A, i.e. getOrElse.

This exemplifies completely algebraic thinking: I could implement optional programs with the ADT you know as Option[A], or with Either[Unit, A], or with a function (Option.fold), but the way you write and reason about these, in the mindset I just laid out, is unchanged.
@vinayakpathak

Vinayak Pathak
@vinayakpathak
yeah, that makes sense

or with a function (Option.fold)

what do you mean by this?

Fabio Labella
@SystemFw
that you can literally represent Option with a function of a certain shape
(this idea is called Church encoding, or more appropriately in a typed setting, Boehm-Berarducci encoding)