These are chat archives for typelevel/cats

27th
Dec 2017
Piotr Gawryś
@Avasil
Dec 27 2017 10:37
What are Free advantages over Tagless?
Luka Jacobowitz
@LukaJCB
Dec 27 2017 10:38
Stack safety
Fabio Labella
@SystemFw
Dec 27 2017 10:38
easier manipulation of AST beyond mere interpretation
it's also worth mentioning a use case that's not in user code
(I prefer tagless in user code)
and that's the implementation of advanced monads
stuff like IO or Stream
which are often Free (or more often, larger datatypes which embed Free)
also, stack safety is only a concern in Scala, it's not fundamental (non-issue in Haskell)
Piotr Gawryś
@Avasil
Dec 27 2017 11:27
Do you have any code examples where it is much easier to express something using Free?
Fabio Labella
@SystemFw
Dec 27 2017 11:45
well, again, when writing user code, I think tagless is easier. That is, when you are interpreting into another pre-existing monad
so the comparison in my second point is not between Free and Final Tagless
because I'm talking about implementation
it's between Free (the idea behind Free at least) and implementing the monad manually
I do have examples of those (it becomes more evident for complicated monads), but not in Scala
generally speaking though, this is stuff that only comes up when writing libraries
Piotr Gawryś
@Avasil
Dec 27 2017 12:18
Oh I see now, thanks :D
Fabio Labella
@SystemFw
Dec 27 2017 12:50
(btw, by "I don't have examples in Scala" I meant simple ones, ofc you can go read the code for scalaz Task or IO, cats IO, fs2 Stream and so on)
there are nice tutorials about this aspect in Haskell
Piotr Gawryś
@Avasil
Dec 27 2017 13:07
Haskell should be fine
Fabio Labella
@SystemFw
Dec 27 2017 13:08
cool
let me dig a few links
Fabio Labella
@SystemFw
Dec 27 2017 13:14
note that this is for the Operational Monad, which is further from the simple data Free f a = Pure a | Join (f (Free f a)) and closer to what we actually have in cats and scalaz
felher
@felher
Dec 27 2017 17:20
Has anyone read https://softwaremill.com/free-tagless-compared-how-not-to-commit-to-monad-too-early/ and can tell me if it's worth looking at? :)
Rob Norris
@tpolecat
Dec 27 2017 17:22
I think it's worth looking at, yes.
Fabio Labella
@SystemFw
Dec 27 2017 17:22
it's worth looking at if you are looking to learn final tagless, but it does get a few things wrong
specifically
However, do we really use any of Futures features anywhere? Is there any reason why this code uses a Future and not, let's say, Task? No! The only things we need are: map, flatMap and unit (which is called Future.successful here). In other words, any monad would do.
I wouldn't do this.
Rob Norris
@tpolecat
Dec 27 2017 17:23
Oh is he trying to abstract side-effects?
bah
Fabio Labella
@SystemFw
Dec 27 2017 17:24
so that bit is (imho quite fundamentally) wrong, but the mechanics of final tagless seem explained well, so definitely worth a read if you haven't come across the technique yet
happy to expand on our objections to if needed, ofc
Filippo Mariotti
@barambani
Dec 27 2017 17:27

Happy holidays, I was experimenting a bit with MonadError and http4s 0.18 and I wanted to ask opinions here about an aspect I’m exploring now. Let’s say I have a service like

final case class Service[F[_] : MonadError[?[_], ServiceError]]

if I want to use this in hatt4s, at some point I will need to have available a MonadError[IO, ServiceError]. To have this I ended up with

implicit val error: MonadError[IO, ServiceError] =
  MonadError[IO, Throwable].adaptErrorType[ServiceError](
    th => ServiceFailure(th.toString),
    sf => new Throwable(s"${sf.toString}”)
  )

Where adaptErrorType is along the line

  def adaptErrorType[F[_], E1, E2](me: MonadError[F, E1])(ff: (E1 => E2), gg: (E2 => E1)): MonadError[F, E2] =
    new MonadError[F, E2] {

      def raiseError[A](e: E2): F[A] =
        (me.raiseError[A] _ compose gg)(e)

      def handleErrorWith[A](fa: F[A])(f: E2 => F[A]): F[A] =
        me.handleErrorWith(fa)(f compose ff)

      def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] =
        me.flatMap(fa)(f)

      def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B] =
        me.tailRecM(a)(f)

      def pure[A](x: A): F[A] =
        me.pure(x)
    }

Where I have to implement a lot of stuf in term of the source MonadError. I was wondering what are the best practices in cases like this and if there’s a quicker way to avoid fixing the MonadError[IO, Throwable] type too early. Many thanks

Piotr Gawryś
@Avasil
Dec 27 2017 18:59
@SystemFw @tpolecat What's the red flag there, overlooking Future's side effectful nature?
Fabio Labella
@SystemFw
Dec 27 2017 19:01
yep
the sentence "just a monad will do"
the same code with Future and Task/IO will behave very differently
and you can't tell, because it's now just F
code deduplication ≠ abstraction
Rob Norris
@tpolecat
Dec 27 2017 19:02
KVStore is side-effecting.
Fabio Labella
@SystemFw
Dec 27 2017 19:02
in particular, if your code does not contain any Future { side effect} or Task { side effect } and indeed a Monad will do, the fact that Future is side effectful makes impossible to reason about it
side effects can't be abstracted over
if instead you want to represent generically the action of encapsulating side effects into pure effects, you need something stronger than Monad, i.e. cats-effect Sync
Rob Norris
@tpolecat
Dec 27 2017 19:05
I think there's a lot of resistance to the fact that you can't use Future for functional programming.
It's just everywhere in mainstream Scala. People can't imagine not having it.
blah
The Problem with Future would be a good conference talk. Everyone will hate you.
Fabio Labella
@SystemFw
Dec 27 2017 19:07
:joy:
Rob Norris
@tpolecat
Dec 27 2017 20:56
Does there exist a scalaz to cats migration guide anywhere?
Seems like people are going to start asking for this.
Ross A. Baker
@rossabaker
Dec 27 2017 21:12
My plan was to write a scalafix once it had enough semantic info. Which maybe it does now, but now I have less scalaz.
Rob Norris
@tpolecat
Dec 27 2017 21:12
I'm drafting a migration guide for doobie 0.4 -> 0.5 for cats users. The scalaz section is :welp:
(Kind of. As long as someone can forge a cats.effect.Async[scalaz.concurrent.Task] instance it will work.)
If you want to convert your codebase to cats it's kind of out of scope. But it would be worth a scalafix effort seems like.
Mike (stew) O'Connor
@stew
Dec 27 2017 21:23
"replace import scalaz., Scalaz. with import cats., cats.implicits. and fix the compile errors"
a scalafix to do it would be super hot
Fabio Labella
@SystemFw
Dec 27 2017 21:25
can you use scalafix to import new libraries?
thinking of dogs, cats-mtl, cats-effect and mouse
Luka Jacobowitz
@LukaJCB
Dec 27 2017 21:26
I think @gabro was interested in doing something of the sort 🙂
Fabio Labella
@SystemFw
Dec 27 2017 21:26
although I actually don't think Task vs IO is that mechanical
Gabriel Volpe
@gvolpe
Dec 27 2017 21:38
Hi @barambani, what's your main goal with the MonadError? Business error handling in Http4s? If so, IMO it is a better approach to define your business errors in something more explicit like a method with signature F[MyError Either A] and just use the MonadError (fixed to Throwable) instance for handling connection errors or any other critical errors raised in the F context by any of the libraries you're using. Here's a simple example: https://github.com/gvolpe/typelevel-stack.g8/blob/master/src/main/g8/src/main/scala/%24package%24/service/UserService.scala
If you still want to perform business error handling via the MonadError you will lose exhaustiveness check at compile time and end up doing something like this to get that feature (super important IMO) back: https://gist.github.com/gvolpe/240607df25e26118b347927b3af09ac8
I'm currently working on a bigger project that will be open sourced in January running on the latest versions of Http4s, Doobie, Circe, Fs2 & Tsec where I think it has now reached a decent quality level of code. I'll be sharing it here first to get some feedback before going public, thought you might be interested.
felher
@felher
Dec 27 2017 22:53
@SystemFw thanks for the input. Will be my bedside reading. I read a bit about final tagless. You recommended a paper once, which introduced ft and contrasted it with the initial (obvious) way to encode a mini language within haskell. Sadly, I then had to move on to other things. But I'm finally returning.
Gabriele Petronella
@gabro
Dec 27 2017 23:35
for the record, I'm managing a migration from scalaz to cats at work using scalafix. The migration code is open source, but it's limited to the few constructs we use at work, namely \/, EitherT, NonEmptyList, Validation a few other syntactic helpers
The tricky part is imports: until scalameta manages scopes properly (work in progress), it's not super trivial to handle wildcard imports during the migration. That is because I want to replace wildcard scalaz imports with precise cats imports. That said, the migration is coming along pretty nicely :)
@tpolecat @rossabaker my current attempt is here, albeit incomplete and limited to my immediate needs https://github.com/gabro/scalaz2cats
Rob Norris
@tpolecat
Dec 27 2017 23:42
Cool.