Where communities thrive

  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
Repo info
Fabio Labella
@labra why do you need an instance of Applicative[R2]? If you have validated of tuples, that you can mapN with a function that takes tuples, the instance you need is ValidatedNel[String, A]
if instead you mapN with a function that operates on A (only operating on the second element of the tuple), you'd need something like Nested
Jose Emilio Labra Gayo
What surprises me is that if R1 compiles...why does R2 not?
I thought that if there was an applicative instance of ValidatedNel[String,A] then there was also an instance of ValidatedNel[String,(A,A)], but maybe I'm missing something...
Fabio Labella
it's different. Given that you have an instance for ValidatedNel[String, A] for all A, you can then instantiate the A type variable to any type, including (A, A). But the opposite is not true: if you look for ValidatedNel[String, (A, A)], ValidatedNel[String, A] does not apply.
you don't need ValidatedNel to show this, Option is enough
when you have (('a -> 1).some, ('b -> 2).some)).mapN { case ((x,y), (z,w)) => ???} the compiler looks for Applicative[Option[?]], and after finding it, instantiates the A (as in, there's an instance for Applicative[Option[A]] forall As), to Tuple2[Symbol, Int].
alternatively, you can say you're looking for ValidatedNel[String, (A, ?)], but that's different (and requires Nested)
Fabio Labella
I can explain it a bit better if you want
Fabio Labella

it's the difference between:

def foo[A]: Foo[A]


def foo2[A]: Foo[(A,A)]

where foo is implicit def applicativeForOption[A]: Applicative[Option[A]]

Fabio Labella

when you do implicitly[Applicative[R1]], you are saying, find me something of type [A] => Applicative[Option[A]] ; once you have this, you can specialise [A] to (B, B). Given the the instance for Option fits the shape [A] => Applicative[Option[A]], it compiles.
When you do implicitly[Applicative[R2]], you are saying, find me something of type [A] => Applicative[Option[(A,A]]. The instance for Option does not have this shape, so it doesn't compile.

* I'm using the fake type [A] => Foo[A] to represent polymorphic methods def foo[A]: Foo[A], Scala does not have first class polymorphic functions

Raphael Mäder
Hi everyone. I have this code in a unit test:
val m = mock[PageRepository[IO]].smart
m.tearDown returns IO { None }
and I get a codegen.java.lang.Object$MockitoMock$862296327 cannot be cast to cats.effect.IO exception. Does anyone know how to fix this? I'm quite new to cats and I'm unsure how to solve this, especially since the IO class is relatively new and I can't find anything about this issue on google :) thanks!
(the exception is thrown on the second line; stack trace doesn't provide more information)
Harrison Houghton
I'm not very experienced with Mockito, but I think you might be running into an issue with mock only getting the type PageRepository[_]
On account of erasure. Is that a scala mockito wrapper?
Raphael Mäder
Yes, from the Specs2 library. I'll read about type erasure, maybe I can find something. Thanks for the hint.
Harrison Houghton
Also, what is PageRepository?
If you're writing code that's parameterized over an arbitrary effect type, often you can make testing easier by replacing the effect with a less general one.
Alexandru Nedelcu
Hi folks, I need the Cats logo. Where can I find it?
Ian Macalinao
Can .map still be used on something with a Functor typeclass instance? Or do I need special imports for that syntax to work?
I'm no longer able to .map over something but if I do functor.map(thing)(fn) it compiles
Rob Norris
What is the type of thing and what cats imports do you have?
Normally you want cats.implicits._ and you want to compile with -Ypartial-unification
To get all the syntax
Fabio Labella
crucially, if you have cats.implicits._, you don't want to have any other implicit imports like syntax or instances @macalinao
Anatolii Kmetiuk

Hi all!

Can anyone explain me how Cats' Free Monad compares to Haskell's one?

Both in Scala and Haskell we seem to have Free programs as ASTs structures stored in memory during the runtime and executed by a separate instruction, usually involving an interpreter.

In Haskell, taking examples here, in order to run the free program, we appear to pass it to an interpreter function directly: one (interpreter is runGame), two (runWeb interpreter). In Scala, we need usually execute by calling a pre-defined interpret with the program and the interpreter, framework style.

In Haskell, the interpreters match on reifications of monad's methods: one, two (I am not very familiar with Haskell, but Return and :>>= look very much like their Pure and FlatMapped counterparts from Scala, correct me if I am wrong here). In Scala, it is in principle impossible to write an interpreter aware of these reifications, since they are private in Cats' implementation.

The Haskell versions make a lot of sense: you are able to define the semantics of the execution of the sequence of monadic method calls. In Cats, this semantics is pre-defined and final, and the emphasis is made on the semantics of individual statements. However, in the official tutorial, you can have the def program: KVStore[Option[Int]] = ... with the flexibility in put, update etc without free monads:

def program[F[_]: Monad](implicit ops: KvOps[F]) =
  for {
    _ <- ops.put("wild-cats", 2)
    _ <- ops.update[Int]("wild-cats", (_ + 12))

Where ops contains the same info as the interpreter, namely the implementation of the domain-specific methods. By switching F and the implicit parameter, you can execute the same program against many backends, with the same type safety as we had with free monads.

E.g. def impureCompiler: KVStoreA ~> Id = ... becomes:

implicit object IdOps extends KvOps[Id] {

  val kvs = mutable.Map.empty[String, Any]

  def put(k, v) = ...

Much less hassle, same effect (inspired by frees.io patterns).

My question is the following: is not the main power of a Free structure in that you are able to treat the sequence of monadic ops as a structure, and hence have perfect control on how to execute the structure? Is this not how Haskell does this (again, not very familiar with it, so I can be wrong here)? If so, why is the execution logic in Cats final, and the reification classes - private?

Fabio Labella
@anatoliykmetyuk You are looking at operational in Haskell, which is actually closer to Scala's version of Free than to the basic Haskell version
the reason I'm mentioning this is that in operational you are not actually pattern matching on the structure (which is private there as well)
but on a "view" over it
and you can do the same with cats Free, using fold
Fabio Labella
however, in both cases, most of the time your interpretation pattern is the one defined in cats foldMap or compile, hence why most of the examples are expressed using those
in the second part of your example, you are using final tagless style, which is also a great choice (and my preferred approach)
Anatolii Kmetiuk
Is it possible to use fold outside the free package though? Seen that the free classes are private.
Fabio Labella
yes, because fold takes as input the two functions representing the bodies of your two cases pattern matches
notice I said two cases, but the actual classes are more than two
this is a common technique: "morally", free has only two cases (Pure and Roll), but the implementation has more for implementation reasons (stack safety)
btw, with operational is the same: the pattern matches you see there are actually pattern synonyms, the actual data structure is different (and law breaking), so we expose a safe "view" over it
Anatolii Kmetiuk
Roll? I can't see it defined here.
Fabio Labella
so the very basic definition of Free is this data Free f a = Pure a | Roll (f (Free f a))
there are two cases, either the computation is terminating with a pure value, or there is another monadic layer
Anatolii Kmetiuk
Can FlatMapped be expressed in terms of these two only?
Fabio Labella
yes, but the usage of this version is less nice
in particular, you need a Functor instance for your data type
it all comes down to the fact that we can express the monad typeclass in two ways (I'm ignoring applicative for a second)
class Monad m where
    pure :: a -> m a
     (>>=) :: m a -> (a -> m b) -> m b
trait Monad[M[_]] {
   def pure[A](a: A): M[A]
   def flatMap[A, B](ma: M[A])(k: A => M[B]): M[B]