These are chat archives for typelevel/cats

8th
Dec 2017
Zenhue Song
@bigknife
Dec 08 2017 03:25
Execuse me, mapN for tuples of FreeApplicative does not work! I've import cats.implicits._ cats.free._, Did I loose some imports ?
Rob Norris
@tpolecat
Dec 08 2017 03:27
Hm. Are you compiling with -Ypartial-unification?
Zenhue Song
@bigknife
Dec 08 2017 03:30
No. Let me try to add it
Zenhue Song
@bigknife
Dec 08 2017 03:35
Not work yet! I think I need not add -Ypartial-unification, because I use scala 2.12.4, right?
Christopher Davenport
@ChristopherDavenport
Dec 08 2017 03:36
Still necessary everywhere.
Zenhue Song
@bigknife
Dec 08 2017 03:41
ohh, Yeah! It works. thanks @tpolecat and @ChristopherDavenport very much
Rob Norris
@tpolecat
Dec 08 2017 03:41
:+1:
They can't turn it on by default. It breaks some existing stuff … I think ScalaTest in particular. I talked to Adriaan about it for a while and his conclusion was that it has to remain optional.
MOHAMMEDI Haroune
@mohammedi-haroune
Dec 08 2017 08:35

Hello everyone,
I'm unable to define a Functor for my abstract class Foo[V : Monoid] that have a type constraint. this is because of the map method of Functor which takes a B parameters which is not a Monoid.

My question is how and where can I add such constraint ?

Here's a sample from what I'm trying to do :

import cats.Functor
import cats.kernel.Monoid

abstract class Foo[A : Monoid] {
  val a: A
}

object Foo {
  implicit def FooFunctor = new Functor[Foo] {
    override def map[A, B](fa: Foo[A])(f: (A) => B) = new Foo[B] {
      override val a: B = f(fa.a)
    }
  }
}

this raise the following exception :

Error:(12, 59) could not find implicit value for evidence parameter of type cats.kernel.Monoid[B]
    override def map[A, B](fa: Foo[A])(f: (A) => B) = new Foo[B] {

My first solution was adding the constraint in the map definition (override def map[A, B : Monoid]) but this is not legal because this will change the definition of the function in Functor and will raise the Exception :

Error:(12, 18) method map overrides nothing.

Can anyone please help me get out of this ? any suggestion would be appreciated.

Adelbert Chang
@adelbertc
Dec 08 2017 08:41
@mohammedi-haroune you cant
Functor requires it to work for any A and B
no constraints
MOHAMMEDI Haroune
@mohammedi-haroune
Dec 08 2017 08:43
@adelbertc so there's no solution for my use case ? not that using functors this way will ease my life a lot
Adelbert Chang
@adelbertc
Dec 08 2017 08:44
if you have Foo defined the way you have there, nope
depending on what your Foo actually looks like you might be able to bubble the constraint down on a method-by-method basis
and maybe you can implement map without a class-level constraint
but if map-ing on Foo requires Monoid, then its not a Functor
MOHAMMEDI Haroune
@mohammedi-haroune
Dec 08 2017 08:46
got it thanks a lot
in my use case Foo requires a Monoid so that I can create a Monoid[Foo[A]]
Adelbert Chang
@adelbertc
Dec 08 2017 08:47
you can shift that down to the definition site
make it Foo[A]
and then when you define the instance just do
implicit def fooMonoid[A: Monoid]: Monoid[Foo[A]]
MOHAMMEDI Haroune
@mohammedi-haroune
Dec 08 2017 08:48
seems to be the right way to do. I'll give a try. thanks a lot @adelbertc
Adelbert Chang
@adelbertc
Dec 08 2017 08:48
:+1:
in general you want to avoid class-level constraints, and just constrain on a case by case basis
Travis Brown
@travisbrown
Dec 08 2017 10:13
I know I'm venturing into blasphemy here, but how often when you move a constraint from the class level to the method level do you use that class with a type that doesn't satisfy the constraint you started with?
I understand the argument for method-level constraints and use them 95% of the time, I just think in Scala specifically sometimes concision + less danger of weird incoherence stuff + efficiency might outweigh elegance + a little more polymorphism you're not going to use anyway.
Harrison Houghton
@hrhino
Dec 08 2017 11:25
Isn't part of the argument that by moving the constraints to only the methods which should need them you can take advantage of parametericity to reason about those methods that it was left off?
I doubt that moving the constraint like that ever has a benefit in terms of making the class usable with a greater set of types.
i.e. the polymorphism isn't there to use, it's to stop you doing funny business.
Travis Brown
@travisbrown
Dec 08 2017 11:30
@hrhino fwiw there are some common cases where it definitely does make the class usable with more types (e.g. the Ordering on List#sorted)
(i.e. in practice)
Harrison Houghton
@hrhino
Dec 08 2017 11:34
Oh, yeah, sorry, I didn't mean to say that it's useless. Rather, I can't imagine that it happens often that someone writes a SortedList, reads Brian's post, moves the class constraint, and then notices that they have List.
Obviously that's contrived but still.
Travis Brown
@travisbrown
Dec 08 2017 11:34
right, agreed.
and I'm also in agreement that parametricity is nice, and it's part of the reason I usually follow the standard advice here…
Harrison Houghton
@hrhino
Dec 08 2017 11:37
Performance, if it's a problem, is probably the best argument for the class constraint, but that's on the same spectrum of "gonna rewrite this method as a while loop because hotspot". Not that extreme, obviously, but still generally inadvisable.
Travis Brown
@travisbrown
Dec 08 2017 11:38
I also do think there's a real cognitive cost to having the same three constraints on a dozen methods instead of once in the class def.
(I'm not sure I've ever seen a case quite that extreme, but close)
I feel like sometimes people say / hear "parametricity" as if it's magic and not just a nice property that can be traded off against other nice properties.
Harrison Houghton
@hrhino
Dec 08 2017 11:39
not just a nice property that can be traded off against other nice properties.
I agree.
It's a nice property to start with, IMHO, but you can always decide it's not worth it.
The other thing that comes to mind is monad transformers. Often a monad transformer is also an "applicative transformer" (for some of it's methods) and by referencing the Monad constraint at the class level you lose out on being able to use the "same concept" when all you need is an Applicative.
Travis Brown
@travisbrown
Dec 08 2017 11:44
yeah, good point.
Artur Soler
@ArturSoler
Dec 08 2017 18:54
working with the State monad and its methods get, modify, inspect, etc., I find myself having to explicitly annotate their type parameters all the time. I find it a bit cumbersome so just asking in case I'm missing something and there's a solution for that
Rob Norris
@tpolecat
Dec 08 2017 18:58
I have had cases in the past where I have to annotate the first one in a for-comp but the following ones are inferred ok. But it's been a while.
Travis Brown
@travisbrown
Dec 08 2017 19:11
@ArturSoler I've used a MonadState instance directly just for syntax, as a way essentially of partially applying some type parameters, but it's now banished to cats-mtl.
Adelbert Chang
@adelbertc
Dec 08 2017 19:11
excuse you, it has been liberated* to cats-mtl ;)