Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Yuriy Badalyantc
@LMnet
Hi! Why cats contains Order typeclass when we have Ordering in the standart library?
felher
@felher
Hey folks. In the introductionary FP course I'm giving we are currently working our way through monads. The theoretical groundwork has been done ( operations and laws ) and it's time to go through a few monads as examples and see how and when to use them. They have already seen Option,Either, and State (and, kind of, List). I'd like to do three more examples. What monads would you suggest? Currently I'm thinking about Reader and Writer.
Andi Miller
@andimiller
I'd probably go for Eval or IO
Fabio Labella
@SystemFw
@felher Reader is not super interesting (ReaderT/Kleisli is, but that's a transformer), but I'd do it anyway . I'd go for List a bit more (behaves "weirdly" which is good to break false assumptions, and prepares you for fs2.Stream), and more importantly IO
however IO requires some subtlety when teaching it, so you might want to make sure they know how to write code with algebras first
and by that I mean code that doesn't use any specific details of the datatypes they're using, but only the algebras defined for them
for example, write code on State without using s => (a, s), but only the combinators
the reason for that is that you want them to get used to IO as an opaque entity imho
Fabio Labella
@SystemFw
I have other examples but it kinda depends on whether you want to focus on how to use monadic abstractions, or how to implement them. Most literature focuses on implementing them on one hand, or in "real world examples" without much explanations on the other, whereas I think developing the sort of thinking that lets you write code using algebras only is very important, and not necessarily always explained well.
Emily Pillmore
@emilypi
@SystemFw Ed just came up with an interesting use for Reader using classy lenses. It's really cool ;)
Oleg Pyzhcov
@oleg-py
@emilypi link? :)
felher
@felher
I think IO/Eval might be a bit too hard just now. Most of them have never done any functional programming until a few weeks ago and now have only had 6 or so lectures to take it in. My goal is to provide a 'intermediate' FP lecture next semester in which IO/Eval would be taught.
@SystemFw could you give an example of what you mean when you say List behaves weirdly?
Fabio Labella
@SystemFw
@emilypi link?
@felher yeah, in that case fair enough
well, weirdly was in quotes
but one example would be the intuition that *> means "and then"

State , check
IO, check

Ok the intuition holds...

List(1,2,3) *> List(4, 5, 6) <--- intuition breaks
again, fs2.Stream behaves like List in many respects so this is a good exercise regardless
felher
@felher
Oh, that's a great example!
Fabio Labella
@SystemFw
the instances for (-> a) (Reader) are also useful for breaking wrong intuitions / expanding one's mind, but they work better in Haskell
Emily Pillmore
@emilypi
@SystemFw when the Lambdaconf vids come out, look for it. I don’t think he’s posted slides, but you could ask him
it was effectively managing logging states using reader + pprism and plens
as opposed to the usual StateT-type solution
Fabio Labella
@SystemFw

Most literature focuses on implementing them on one hand, or in "real world examples" without much explanations on the other, whereas I think developing the sort of thinking that lets you write code using algebras only is very important, and not necessarily always explained well

@felher this really matters to me so I want to expand a bit. Let's take State as an example. In most cases books/tutorial fall in two categories:

  • "let's develop a web server where each request has a request context, to do this we can use State from cats, which has amodify function that we can use in a for comprehension. Don't worry about how it works now...[proceeds with concrete example]"
  • "Abstracting over state can be done with a => (a, s) where each function gets a new copy of the State. If we write down a couple of example we can see that it fits the Monad abstraction. Let's write the instance for Monad"

Obviously they are both useful in different respects, however there are drawbacks:

  • The first approach is good to break the ice/show you that you can write real code in FP, but it doesn't give a lasting understanding imho. You need to understand the foundations.
  • The second is good at explaining State, but it doesn't necessarily give you transferable skills that you can use with other abstractions for which you don't know the internal representation. A typical example where this breaks is when introducing IO.

I like to use a third approach. After having explained what the main algebras bring to the table (Functor lifts 1-arg functions, Applicative lifts n-ary functions, Monad gives you context sensitivity), I present State like this:

State is a datatype representing computations that describe modifications to a value, with the following algebra:

trait State[S, A] // S state, A output
object State {
   def get[S]: State[S, S]
   def set[S](s: S): State[S, Unit]

   implicit def m: Monad[State[S, ?]] // stress that this implies Functor and Applicative
}

and then you have them write programs in this "language", without knowing anything about the internal representation, but only the State algebra (get, set, what the type means, any laws, the monad instance). After they manage to use it like that, you can explain how it's implemented (typically you'll go back and forth a few times in real life). The advantage is that this is aimed to instill the sort of algebraic thinking that is not only one of the biggest advantages of FP, but also necessary when you deal with opaque/complex abstractions like IO or Stream

@emilypi right, the thing with local, I'm been waiting for the talk for a while. That's still ReaderT though I think?
I actually also have a pretty cool use of Reader, but it's advanced so I didn't mention it here
felher
@felher
@SystemFw thanks, this is very good advice.
Emily Pillmore
@emilypi
@SystemFw yeah, basically. I believe it was readert yeah. Very cool stuff
Reader is underrated
So is ReaderT
felher
@felher
@SystemFw I think I will introduce Reader in the way you said. Since reader has only additional operation, ask, I think this is a good place to start.
Fabio Labella
@SystemFw
yeah, that's true
not a lot you can do with Reader alone though
felher
@felher
True. I don't think it's too much of a problem, though. The students will be happy if there is something they can grasp completely and where they have a glue as to how the exam at the end of the semester might look like.
Fabio Labella
@SystemFw
ah, this is in a properly academic setting
fair enough, I've only taught in industry :)
Christopher Davenport
@ChristopherDavenport
Exam Season - PagerDuty
Atleast that’s how I see it. If I have no bugs, I sleep soundly.
Emily Pillmore
@emilypi
In Haskell at least, I find myself using it implicitly often
Less so consciously, more arrows in general
Fabio Labella
@SystemFw
@emilypi I'm not talking in general, just about the fairly specific example of teaching algebras like above. With State only you can have them write quite a few interesting programs, with Reader less so (unless you have ReaderT). Btw my favourite non-obvious use case is using Reader to write shapeless typeclass instances that depend on a runtime value
Emily Pillmore
@emilypi
Ah yeah
Taleb Zeghmi
@talebzeghmi

Hi,
Playing with introduction code http://47deg.github.io/fetch/docs.html#introduction-0

// type Fetch[A] = cats.free.Free[fetch.FetchOp, A] 
def getUser(id: UserId): Fetch[User] = Fetch(id)

for {
  x: User <- getUser(1)
} yield s"${x.id} ${x.username}”

Produces following error:
Error:(105, 23) value filter is not a member of fetch.Fetch[User]

Thoughts on how to get around this?

Taleb Zeghmi
@talebzeghmi
Why is it trying to call withFilter?
Emily Pillmore
@emilypi
because for comprehensions are implemented poorly.
every time you have a predicate on your type like : Type or if foo, it calls withFilter
Oleg Pyzhcov
@oleg-py
or a pattern like (a, _) <- something
basically at the left hand side to the arrow, anything but a simple name is a withFilter call