How to combine type parameter bounds and functors using Cats? - scala

I am encountering a number of use cases where I am end of attempting to write Functor, Applicative, Monad, etc instances in contexts where I am also using type parameter bounds.
For example...
import cats._
trait Preference[A] extends Order[A]
trait SocialWelfareFunction[-CC <: Iterable[P], +P <: Preference[_]]
extends (CC => P)
object SocialWelfareFunction {
def functor: Functor[({ type F[P <: Preference[_]] = SocialWelfareFunction[Iterable[P], P] })#F] = {
???
}
...when I try to compile this I will get the following error.
kinds of the type arguments ([P <: Playground.this.Preference[_]]Playground.this.SocialWelfareFunction[Iterable[P],P]) do not conform to the expected kinds of the type parameters (type F) in trait Monad.
[P <: Playground.this.Preference[_]]Playground.this.SocialWelfareFunction[Iterable[P],P]'s type parameters do not match type F's expected parameters:
type P's bounds <: Playground.this.Preference[_] are stricter than type _'s declared bounds >: Nothing <: Any
How can I write Functor, Applicative, Monad , etc instances for contexts in which I am also using type parameters? Is it even possible? Is there a more appropriate way forward?

(Not a full solution, just a hint requested by OP to further clarify the question)
This example shows how to define Functor instances for type constructors that look almost as if they could be functors, but have several restrictions:
Upper type bound <: UB on type parameter
Require instances of typeclass TC
Here is a way around these two restrictions:
import scala.language.higherKinds
// Your favorite flavour of `Functor`,
// e.g. from `scalaz` or `cats`
trait Functor[F[_]] {
def map[A, B](x: F[A], f: A => B): F[B]
}
// an upper bound
trait UB
// a typeclass
trait TC[X]
// A type constructor that is not a
// functor, because it imposes upper bounds
// on the parameter, and because it requires
// a typeclass `TC` for `X`.
class Foo[X <: UB : TC] {
def map[Y <: UB : TC](f: X => Y): Foo[Y] = ??? /*
some very clever implementation making use of `UB` and `TC`
*/
}
// A Functor that approximates `Foo[X]` for *arbitrary* `X`,
// without any restrictions.
abstract class WrappedFoo[X] { outer =>
type Base <: UB
val base: Foo[Base]
protected val path: Base => X
def map[Y](f: X => Y): WrappedFoo[Y] = new WrappedFoo[Y] {
type Base = outer.Base
val base = outer.base
val path: Base => Y = outer.path andThen f
}
def unwrap[Y <: UB](
implicit
xIsY: X =:= Y,
yTC: TC[Y]
): Foo[Y] = base.map(outer.path andThen xIsY)
}
// Functor instance for `WrappedFoo`
object WrappedFooFunctor extends Functor[WrappedFoo] {
def map[A, B](x: WrappedFoo[A], f: A => B): WrappedFoo[B] = {
x map f
}
def wrap[A <: UB](foo: Foo[A]): WrappedFoo[A] = new WrappedFoo[A] {
type Base = A
val base = foo
val path = identity[A]
}
}
object Example {
// two "good" classes that conform to
// the upper bound and have instances
// of the typeclass
class Good1 extends UB
class Good2(i: Int) extends UB
implicit object Good1TC extends TC[Good1]
implicit object Good2TC extends TC[Good2]
val x1 = new Foo[Good1] // start with "Foo[Good1]"
val f: Good1 => Int = _.toString.length
val g: Int => Good2 = i => new Good2(i)
// Now we would like to go like this:
//
// Foo[Good1] ---f---> Foo[Int] ---g---> Foo[Good2]
//
// The problem is: `Int` does not conform to `UB`,
// and has no `TC` instance.
// Solution:
val x1w = WrappedFooFunctor.wrap(x1)
val intermediate = x1w.map(f) // approximates "Foo[Int]"
val x2w = intermediate.map(g) // wraps "Foo[Good2]"
val x2 = x2w.unwrap // only "Foo[Good2]"
}

Related

Force covariance for Scala abstract type with #uncheckedVariance

Topics of variance are well presented in many place but unfortunately i do not find any place dealing about this topic with abstract types.
Then in an attempt to understand collection i've written following content
trait CollectionOps[+A, +C] {
this: C =>
type CC[B] <: BasicColl[B] // Invariant position
def filter(f: A => Boolean): C
def map[B](f: A => B): CC[B] // CC is in a covariant position but declared invariant via abstract type
}
trait BasicColl[+A] extends CollectionOps[A, BasicColl[A]] {
type CC[B] = BasicColl[B] // this is the problem, the equality
// But if i let inequality: type CC[B] <: BasicColl[B]
}
// Do not compile due to previous equality and invariance on CC
trait BasicColl2[+A] extends BasicColl[A] with CollectionOps[A, BasicColl2[A]] {
type CC[B] = BasicColl2[B]
// But if i let the previous inequality i can writte type CC[B] <: BasicColl2[B]
}
trait Test_With_Abstract_Type_Equality {
// Only BasicColl extist
def coll1: BasicColl[Int]
// We have exact type due to equality of CC with BasicColl
def mapped: BasicColl[Double] = coll1.map(_.toDouble)
// But no specialized inhéritence possible
}
trait Test_With_Abstract_Type_Inequality {
def coll1: BasicColl[Int]
// We have abstract type due to inequality of CC with BasicColl
def mappedWithAbstractTypeDef: BasicColl[Int]#CC[Double] = coll1.map(_.toDouble)
// BasicColl2 can exist
def coll2: BasicColl2[Int]
// We have abstract type due to inequality of CC with BasicColl2
def mappedWithAbstractTypeDef2: BasicColl2[Int]#CC[Double] = coll2.map(_.toDouble)
}
Scala pattern do not use astract type but directly a covariant paremetrized type CC as follow
trait IterableOnceOps[+A, +CC[_], +C]
Covariance has the advantage to facilitating trait mixing.
But using a Higher Kind of this type at type parameter level prevent any extension to class with more than 1 parametrized type where using abstract type allow extension to more complex class at the cost of having abstract type as output.
Here the point i tried that but i m not confident enough about risk of it.
// Redefinition
trait CollectionOps[+A, +C] {
this: C =>
type CC[B] <: BasicColl[B] // Invariant position
def filter(f: A => Boolean): C
def map[B](f: A => B): CC[B] // but CC is in a covariant position
}
// Redefinition
trait BasicColl[+A] extends CollectionOps[A, BasicColl[A]]
trait CollectionOpsLocked1[+A, +CCC[B] <: BasicColl[B], +C] extends CollectionOps[A, C] {
this: C =>
type CC[B] = CCC[B] #uncheckedVariance // this is my question
// If i use CC ONLY in covariant position is there any risk ?
}
trait BasicColl2[+A] extends BasicColl[A] with CollectionOpsLocked1[A, BasicColl2, BasicColl2[A]]
trait BasicColl3[+A] extends BasicColl2[A] with CollectionOpsLocked1[A, BasicColl3, BasicColl3[A]]
trait Test {
def coll1: BasicColl[Int]
def mappedWithAbstractTypeDef: BasicColl[Int]#CC[Double] = coll1.map(_.toDouble)
// BasicColl2 can exist
def coll2: BasicColl2[Int]
def mapped2: BasicColl2[Double] = coll2.map(_.toDouble)
// BasicColl3 can exist
def coll3: BasicColl3[Int]
def mapped3: BasicColl3[Double] = coll3.map(_.toDouble)
}
More generaly is there any risk to use #uncheckedVariance to some place where covariance/contravariance are legit ?

Defining a constructor for a typeclass that takes a method with a type parameter?

I have a situation where none of the solutions that I'm aware of feel like good ones. I am trying to define a typeclass, like the example below, where it has an abstract type S that must implement another typeclass (not shown) Valid[A]. It feels like the easiest way to do this would be to create an apply constructor, which will force the user to enter S and automatically bring in an implicit instance for sIsValid.
The problem with this is that function changeType takes a type parameter. Despite some googling I have not figured out how to write a type annotation for a function that takes a type parameter (this may be because it seems like Scala does not allow anonymous functions with type parameters). Does my approach here seem like a sensible one? If I can provide a type annotation for changeType then the typeclass user can still pass a non-anonymous function to the apply constructor, which seems like a mostly satisfactory solution.
abstract class IsTC[A[_], T] {
// type S is an abstract type rather than type parameter, but must implement Valid[A]
type S
implicit val sIsValid: Valid[S]
def get(self: A[T], i: Int): T
def changeType[_T]: A[_T]
}
object IsTC {
def apply[A[_], T, _S](
fget: (A[T], Int) => T,
fchangeType: // what should this type annotation be?
): IsTC[A, T] { type S = _S } = new IsTC[A, T] {
type S = _S
def get(self: A[T], i: Int) = fget(self, i)
def changeType[_T]: A[_T] = fchangeType[_T]
}
}
Any help/thoughts gratefully received.
Scala 2 doesn't support polymorphic functions. Polymorphic can be methods, not values. And functions are values. Polymorphic functions can be emulated with wrappers
// for [A] => (a: A) => B[A]
trait Poly {
def apply[A](a: A): B[A]
}
or
// for [A <: U] => (a: A) => B[A]
trait Poly[U] {
def apply[A <: U](a: A): B[A]
}
like shapeless.Poly. They generalize ordinary functions
trait Function[A, B] {
def apply(a: A): B
}
Try
object IsTC {
def apply[A[_], T, _S](
fget: (A[T], Int) => T,
fchangeType: FchangeType[A]
): IsTC[A, T] { type S = _S } = new IsTC[A, T] {
override type S = _S
override implicit val sIsValid: Valid[_S] = ???
override def get(self: A[T], i: Int) = fget(self, i)
override def changeType[_T]: A[_T] = fchangeType[_T]
}
}
trait FchangeType[A[_]] {
def apply[X]: A[X]
}
Dotty has polymorphic functions [A <: U] => (a: A) => f[A](a) of polymorphic function types [A <: U] => A => B[A] but there is implementation restriction: polymorphic function types must have a value parameter so you can't have polymorphic function type [X] => A[X] (not to be confused with a type lambda [X] =>> A[X]) currently even there.
Also (besides emulation with wrappers) some polymorphic types can be expressed via existential types: [A] => B[A] => C (for constant C) is actually B[_] => C.
This is because ∀a: (B(a) => C) ≡ (∃a: B(a)) => C.

Scala: higher-kinded types, type projections and type mismatch error

I have the following code:
trait M[Type[_]]{
type T[X] = Type[X]
def from[A](f: T[A]): A
}
class ListM extends M[List]{ def from[A](f: T[A]) = f.head }
class Trans[A, X[_], B <: M[X]](val r: X[Option[A]])
trait CurriedTrans[X[_], B <: M[X]]{ type Type[A] = Trans[A, X, B] }
class TransM[X[_], B <: M[X]](val b: B) extends M[CurriedTrans[X, B]#Type]{
def from[A] = (f: T[A]) => b.from(f.r).get
}
and I can instantiate variables of type TransM in two ways:
val x1 = new TransM[List, ListM](new ListM)
val x2 = new TransM[ListM#T, ListM](new ListM)
I think ListM#T is redundant type parameter, so I'm trying to eliminate it:
trait M{
type T[X]
def from[A](f: T[A]): A
}
class ListM extends M {
type T[X] = List[X]
def from[A](f: T[A]) = f.head
}
class Trans[A, B <: M](val r: B#T[Option[A]])
class TransM[B <: M](val b: B) extends M {
type T[X] = Trans[X, B]
def from[Y] = (f: T[Y]) => b.from(f.r).get
}
to instantiate variable as
val x = new TransM[ListM](new ListM)
Unfortunately, the second implementation can't be compiled because of a type mismatch error:
type mismatch;
found : f.r.type (with underlying type B#T[Option[Y]])
required: TransM.this.b.T[?]
def from[Y] = (f: T[Y]) => b.from(f.r).get
^
Can I fix this issue and simplify my code or should I write boilerplate ListM#T everywhere?
#ziggystar says it: Drop the bound B and use M[X] directly:
class TransM[X[_]](val b: M[X]) extends M[CurriedTrans[X, M[X]]#Type] {
def from[A](f: T[A]) = b.from(f.r).get
}
val x1 = new TransM(new ListM)
You could consider to do the same for Trans and CurriedTrans. If you need the inner type of M, you can always expose it through a type member of Trans and CurriedTrans.

What are the limitations on inference of higher-kinded types in Scala?

In the following simplified sample code:
case class One[A](a: A) // An identity functor
case class Twice[F[_], A](a: F[A], b: F[A]) // A functor transformer
type Twice1[F[_]] = ({type L[α] = Twice[F, α]}) // We'll use Twice1[F]#L when we'd like to write Twice[F]
trait Applicative[F[_]] // Members omitted
val applicativeOne: Applicative[One] = null // Implementation omitted
def applicativeTwice[F[_]](implicit inner: Applicative[F]): Applicative[({type L[α] = Twice[F, α]})#L] = null
I can call applicativeTwice on applicativeOne, and type inference works, as soon as I try to call it on applicativeTwice(applicativeOne), inference fails:
val aOK = applicativeTwice(applicativeOne)
val bOK = applicativeTwice[Twice1[One]#L](applicativeTwice(applicativeOne))
val cFAILS = applicativeTwice(applicativeTwice(applicativeOne))
The errors in scala 2.10.0 are
- type mismatch;
found : tools.Two.Applicative[[α]tools.Two.Twice[tools.Two.One,α]]
required: tools.Two.Applicative[F]
- no type parameters for method applicativeTwice:
(implicit inner: tools.Two.Applicative[F])tools.Two.Applicative[[α]tools.Two.Twice[F,α]]
exist so that it can be applied to arguments
(tools.Two.Applicative[[α]tools.Two.Twice[tools.Two.One,α]])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : tools.Two.Applicative[[α]tools.Two.Twice[tools.Two.One,α]]
required: tools.Two.Applicative[?F]
Why wouldn't "?F" match with anything (of the right kind) ?
Ultimately I'd like applicativeTwice to be an implicit function, but I'd have to get the type inference working first.
I have seen similar questions, and the answers pointed to limitations in the type inference algorithms. But this case seems pretty limitative, and must be quite an annoyance in monad transformers, so I suspect I'm missing some trick to work around this.
You've hit a common annoyance: SI-2712. For clarity, I'm going to minimize your code a bit:
import language.higherKinds
object Test {
case class Base[A](a: A)
case class Recursive[F[_], A](fa: F[A])
def main(args: Array[String]): Unit = {
val one = Base(1)
val two = Recursive(one)
val three = Recursive(two) // doesn't compile
println(three)
}
}
This demonstrates the same type error as yours:
argument expression's type is not compatible with formal parameter type;
found : Test.Recursive[Test.Base,Int]
required: ?F
val three = Recursive(two) // doesn't compile
^
First a bit of syntax and terminology you probably already know:
In Scala we say that a plain, unparameterized data type (such as Int) has kind _. It's monomorphic.
Base, on the other hand, is parameterized. we can't use it as the type of a value without providing the type it contains, so we say has kind _[_]. It's rank-1 polymorphic: a type constructor that takes a type.
Recursive goes further still: it has two parameters, F[_] and A. The number of type parameters don't matter here, but their kinds do. F[_] is rank-1 polymorphic, so Recursive is rank-2 polymorphic: it's a type constructor that takes a type constructor.
We call anything rank two or above higher-kinded, and this is where the fun starts.
Scala in general doesn't have trouble with higher-kinded types. This is one of several key features that distinguishes its type system from, say, Java's. But it does have trouble with partial application of type parameters when dealing with higher-kinded types.
Here's the problem: Recursive[F[_], A] has two type parameters. In your sample code, you did the "type lambda" trick to partially apply the first parameter, something like:
val one = Base(1)
val two = Recursive(one)
val three = {
type λ[α] = Recursive[Base, α]
Recursive(two : λ[Int])
}
This convinces the compiler that you're providing something of the correct kind (_[_]) to the Recursive constructor. If Scala had curried type parameter lists, I'd definitely have used that here:
case class Base[A](a: A)
case class Recursive[F[_]][A](fa: F[A]) // curried!
def main(args: Array[String]): Unit = {
val one = Base(1) // Base[Int]
val two = Recursive(one) // Recursive[Base][Int]
val three = Recursive(two) // Recursive[Recursive[Base]][Int]
println(three)
}
Alas, it does not (see SI-4719). So, to the best of my knowledge, the most common way of dealing with this problem is the "unapply trick," due to Miles Sabin. Here is a greatly simplified version of what appears in scalaz:
import language.higherKinds
trait Unapply[FA] {
type F[_]
type A
def apply(fa: FA): F[A]
}
object Unapply {
implicit def unapply[F0[_[_], _], G0[_], A0] = new Unapply[F0[G0, A0]] {
type F[α] = F0[G0, α]
type A = A0
def apply(fa: F0[G0, A0]): F[A] = fa
}
}
In somewhat hand-wavey terms, this Unapply construct is like a "first-class type lambda." We define a trait representing the assertion that some type FA can be decomposed into a type constructor F[_] and a type A. Then in its companion object, we can define implicits to provide specific decompositions for types of various kinds. I've only defined here the specific one that we need to make Recursive fit, but you could write others.
With this extra bit of plumbing, we can now do what we need:
import language.higherKinds
object Test {
case class Base[A](a: A)
case class Recursive[F[_], A](fa: F[A])
object Recursive {
def apply[FA](fa: FA)(implicit u: Unapply[FA]) = new Recursive(u(fa))
}
def main(args: Array[String]): Unit = {
val one = Base(1)
val two = Recursive(one)
val three = Recursive(two)
println(three)
}
}
Ta-da! Now type inference works, and this compiles. As an exercise, I'd suggest you create an additional class:
case class RecursiveFlipped[A, F[_]](fa: F[A])
... which isn't really different from Recursive in any meaningful way, of course, but will again break type inference. Then define the additional plumbing needed to fix it. Good luck!
Edit
You asked for a less simplified version, something aware of type-classes. Some modification is required, but hopefully you can see the similarity. First, here's our upgraded Unapply:
import language.higherKinds
trait Unapply[TC[_[_]], FA] {
type F[_]
type A
def TC: TC[F]
def apply(fa: FA): F[A]
}
object Unapply {
implicit def unapply[TC[_[_]], F0[_[_], _], G0[_], A0](implicit TC0: TC[({ type λ[α] = F0[G0, α] })#λ]) =
new Unapply[TC, F0[G0, A0]] {
type F[α] = F0[G0, α]
type A = A0
def TC = TC0
def apply(fa: F0[G0, A0]): F[A] = fa
}
}
Again, this is completely ripped off from scalaz. Now some sample code using it:
import language.{ implicitConversions, higherKinds }
object Test {
// functor type class
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
// functor extension methods
object Functor {
implicit class FunctorOps[F[_], A](fa: F[A])(implicit F: Functor[F]) {
def map[B](f: A => B) = F.map(fa)(f)
}
implicit def unapply[FA](fa: FA)(implicit u: Unapply[Functor, FA]) =
new FunctorOps(u(fa))(u.TC)
}
// identity functor
case class Id[A](value: A)
object Id {
implicit val idFunctor = new Functor[Id] {
def map[A, B](fa: Id[A])(f: A => B) = Id(f(fa.value))
}
}
// pair functor
case class Pair[F[_], A](lhs: F[A], rhs: F[A])
object Pair {
implicit def pairFunctor[F[_]](implicit F: Functor[F]) = new Functor[({ type λ[α] = Pair[F, α] })#λ] {
def map[A, B](fa: Pair[F, A])(f: A => B) = Pair(F.map(fa.lhs)(f), F.map(fa.rhs)(f))
}
}
def main(args: Array[String]): Unit = {
import Functor._
val one = Id(1)
val two = Pair(one, one) map { _ + 1 }
val three = Pair(two, two) map { _ + 1 }
println(three)
}
}
Note (3 years later, July 2016), scala v2.12.0-M5 is starting to implement SI-2172 (support for higher order unification)
See commit 892a6d6 from Miles Sabin
-Xexperimental mode now only includes -Ypartial-unification
It follows Paul Chiusano's simple algorithm:
// Treat the type constructor as curried and partially applied, we treat a prefix
// as constants and solve for the suffix. For the example in the ticket, unifying
// M[A] with Int => Int this unifies as,
//
// M[t] = [t][Int => t] --> abstract on the right to match the expected arity
// A = Int --> capture the remainder on the left
The test/files/neg/t2712-1.scala includes:
package test
trait Two[A, B]
object Test {
def foo[M[_], A](m: M[A]) = ()
def test(ma: Two[Int, String]) = foo(ma) // should fail with -Ypartial-unification *disabled*
}
And (test/files/neg/t2712-2.scala):
package test
class X1
class X2
class X3
trait One[A]
trait Two[A, B]
class Foo extends Two[X1, X2] with One[X3]
object Test {
def test1[M[_], A](x: M[A]): M[A] = x
val foo = new Foo
test1(foo): One[X3] // fails with -Ypartial-unification enabled
test1(foo): Two[X1, X2] // fails without -Ypartial-unification
}

Type upper bound in Scala Mapper/Record traits

I am puzzled by what seems to be a standard pattern in the Lift's Mapper and Record frameworks:
trait Mapper[A<:Mapper[A]] extends BaseMapper {
self: A =>
type MapperType = A
What does it mean with regard to the type parameter of the Mapper trait? The type A, which is a parameter of Mapper, is required to be a subclass of Mapper[A], how is it even possible, or may be I just don't understand the meaning of this definition.
This pattern is used to be able to capture the actual subtype of Mapper, which is useful for accepting arguments of that exact type in methods.
Traditionally you can't declare that constraint:
scala> trait A { def f(other: A): A }
defined trait A
scala> class B extends A { def f(other: B): B = sys.error("TODO") }
<console>:11: error: class B needs to be abstract,
since method f in trait A of type (other: A)A is not defined
(Note that A does not match B)
class B extends A { def f(other: B): B = sys.error("TODO") }
While when you have access to the precise type you can do:
scala> trait A[T <: A[T]] { def f(other: T): T }
defined trait A
scala> class B extends A[B] { def f(other: B): B = sys.error("TODO") }
defined class B
Note that this is also possible via bounded type members:
trait A { type T <: A; def f(other: T): T }
class B extends A { type T <: B; def f(other: T): T = sys.error("TODO") }