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
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
@SystemFw
I can explain it a bit better if you want
Fabio Labella
@SystemFw

it's the difference between:

def foo[A]: Foo[A]
foo[(B,B)]

and:

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

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

Fabio Labella
@SystemFw

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
@randm-ch
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
@hrhino
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
@randm-ch
Yes, from the Specs2 library. I'll read about type erasure, maybe I can find something. Thanks for the hint.
Harrison Houghton
@hrhino
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
@alexandru
Hi folks, I need the Cats logo. Where can I find it?
lxb
@0x6c7862_twitter
Ian Macalinao
@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
@tpolecat
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
@SystemFw
crucially, if you have cats.implicits._, you don't want to have any other implicit imports like syntax or instances @macalinao
Anatolii Kmetiuk
@anatoliykmetyuk

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
@SystemFw
@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
@SystemFw
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
@anatoliykmetyuk
Is it possible to use fold outside the free package though? Seen that the free classes are private.
Fabio Labella
@SystemFw
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
@anatoliykmetyuk
Roll? I can't see it defined here.
Fabio Labella
@SystemFw
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
@anatoliykmetyuk
Can FlatMapped be expressed in terms of these two only?
Fabio Labella
@SystemFw
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)
one
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]
}
or
class (Functor m) => Monad m where
   pure :: a -> m a
   join :: m (m a) -> m a
trait Monad[M[_] extends Functor[M] {
    def pure[A](a: A): M[A]
    def flatten[A](mma: M[M[A]]):  M[A]
}
these two are perfectly equivalent
Fabio Labella
@SystemFw
the original, simpler free is derived from this latter version, whereas operational (and cats Free) are from the first version
the advantage is that you don't need a Functor instance for your ADT, and that you don't need an extra parameter for your data types representing the next step in the computation
in more technical terms, operational and cats Free are said to be Free over Coyoneda