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

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.

Related

In scala, what can be done to prevent compiler from cyclic summoning of implicit premises? And how to avoid them

I'm writing an implementation for Curry-Howard isomorphism in scala, a family of proofs can be defined as an object implementing the following trait:
(the full code repo is uploaded to https://github.com/tribbloid/shapesafe/blob/djl/prove-debug/macro/src/main/scala/org/shapesafe/core/shape/unary/WithNames.scala)
trait ProofSystem[OUB] { // TODO: no IUB?
trait Proposition extends Serializable {
type Codomain <: OUB
def value: Codomain
}
case object Proposition {
type Aux[O <: OUB] = Proposition {
type Codomain = O
}
type Lt[+O <: OUB] = Proposition {
type Codomain <: O
}
// Can't use Aux, syntax not supported by scala
trait Of[O <: OUB] extends Proposition {
final type Codomain = O
}
case class ToBe[O <: OUB](override val value: O) extends Of[O]
}
// doesn't extend T => R intentionally
// each ProofSystem use a different one to alleviate search burden of compiler (or is it redundant?)
trait CanProve[-I, +P <: Proposition] {
def apply(v: I): P
final def valueOf(v: I): P#Codomain = apply(v).value // TODO: this should be real apply? The above should be 'prove'
}
object CanProve {}
/**
* representing 2 morphism:
*
* - value v --> value apply(v)
*
* - type I --> type O
*
* which is why it uses =>>
* #tparam I src type
* #tparam P tgt type
*/
class =>>^^[-I, P <: Proposition](
val toProof: I => P
) extends CanProve[I, P] {
override def apply(v: I): P = toProof(v)
}
type -->[-I, O <: OUB] = CanProve[I, Proposition.Aux[O]]
type ~~>[-I, +O <: OUB] = CanProve[I, Proposition.Lt[O]]
class =>>[-I, O <: OUB](
val toOut: I => O
) extends =>>^^[I, Proposition.ToBe[O]](v => Proposition.ToBe(toOut(v)))
def from[I]: Factory[I] = new Factory[I]()
class Factory[I]() {
def =>>^^[P <: Proposition](fn: I => P) = new (I =>>^^ P)(fn)
def =>>[O <: OUB](fn: I => O) = new (I =>> O)(fn)
}
def at[I](v: I) = new Summoner[I](v)
class Summoner[I](v: I) extends Factory[I] {
implicit def summon[P <: Proposition](
implicit
ev: CanProve[I, P]
): P = ev.apply(v)
implicit def summonValue[P <: Proposition](
implicit
ev: CanProve[I, P]
): P#Codomain = summon(ev).value
}
}
In one particular case, the compiler got into a dead loop when 2 implicits are defined in a scope:
case class WithNames[
S1 <: Shape,
N <: Names
](
s1: S1,
newNames: N
) extends Shape {}
object WithNames {
// TODO: DEAD LOOP!
implicit def axiom[
P1 <: LeafShape,
N <: Names,
HO <: HList,
O <: LeafShape
](
implicit
zip: ZipWithKeys.Aux[N#Keys, P1#_Dimensions#Static, HO],
toShape: LeafShape.FromRecord.==>[HO, O]
): WithNames[P1, N] =>> O = {
from[WithNames[P1, N]].=>> { src =>
val keys: N#Keys = src.newNames.keys
val p1: P1 = src.s1
val values: P1#_Dimensions#Static = p1.dimensions.static
val zipped: HO = values.zipWithKeys(keys)
LeafShape.FromRecord(zipped)
}
}
implicit def theorem[
S1 <: Shape,
N <: Names,
P1 <: LeafShape,
O <: LeafShape
](
implicit
lemma1: S1 ~~> P1,
lemma2: WithNames[P1, N] --> O
): WithNames[S1, N] =>> O = {
from[WithNames[S1, N]].=>> { src =>
val p1: P1 = lemma1.valueOf(src.s1)
lemma2.valueOf(
src.copy(p1)
)
}
}
}
The compiler seems to be stuck on a cyclic proof resolution: it tries to fulfil lemma2 of theorem with itself. If I merge 2 implicits into 1, the problem disappeared:
implicit def asLeaf[
S1 <: Shape,
P1 <: LeafShape,
N <: Names,
HO <: HList,
O <: LeafShape
](
implicit
lemma: S1 ~~> P1,
zip: ZipWithKeys.Aux[N#Keys, P1#_Dimensions#Static, HO],
toShape: LeafShape.FromRecord.==>[HO, O]
): WithNames[S1, N] =>> O = {
from[WithNames[S1, N]].=>> { src =>
val keys: N#Keys = src.newNames.keys
val p1: P1 = lemma.valueOf(src.s1)
val values: P1#_Dimensions#Static = p1.dimensions.static
val zipped: HO = values.zipWithKeys(keys)
LeafShape.FromRecord(zipped)
}
}
So my questions are:
Why this could happen and what change of the scala compiler algorithm could eliminate any cyclic search for proves?
How to manually circumvent this error?
I also realised that the canonical implementation of homotopy type theory (https://github.com/siddhartha-gadgil/ProvingGround) actually does most of the inference in runtime, instead of compile-time, which seems to be defeating the purpose. Perhaps this bug is part of the reason?

Using a type constructor in a type refinement

I'm having a problem which is probably best expressed in code - a simplified example below:
abstract class MainTC[A] {
type E
// A type constructor for the implementing type:
type CN[_]
implicit val ev: CN[A] =:= A // check that CN works as a type constructor for A
def get(self: A): E
def set[B](self: A, other: B): CN[B] { type E = B }
def convert[B](self: A)(implicit conv: Convert[A, E, B]) = conv.convert(self)(this)
}
abstract class Convert[A, _E, B] {
type Out
def convert(self: A)(implicit isMain: MainTC[A] { type E = _E }): Out
}
object Convert {
implicit def convertDoubleToInt[A, _CN[_]](implicit
isMain: MainTC[A] { type E = Double; type CN[_] = _CN[_] },
): Convert[A, Double, Int] = new Convert[A, Double, Int] {
type Out = _CN[Int] { type E = Int }
def convert(self: A): Out = {
val toInt = isMain.get(self).toInt
isMain.set[Int](self, toInt)
// type mismatch -
// found: isMain.CN[Int]{type E = Int} (which expands to) _CN[_]{type E = Int}
// required: this.Out (which expands to) _CN[Int] {type E = Int}
}
}
}
The basic situation here is quite simple - I am using a typeclass to implement the polymorphic convert function. The tricky part is that I am storing a type constructor as an abstract type within the MainTC typeclass. When converting in the Convert typeclass, I would then like to use that type constructor to create a new type as the output type (eg, CN[Int]). I am trying to use something like the Aux pattern to achieve this, with _CN[_] being created as a type alias for isMain.CN[_]. However, it's not working (error message in the code). If anyone could lend me a hand I'd be most grateful.
do you mean type CN[_] = _CN[_] or type CN[X] = CN[X]? If you change it to the latter, you run into the issue that
def convert(self: A): Out
can't implement
def convert(self: A)(implicit isMain: MainTC[A] { type E = _E }): Out
because it's missing the implicit parameter. Keep in mind that Scala implicits don't have to be coherent: convertDoubleToInt's (isMain: MainTC[A] {type E = _ E}).TC isn't the same as convert's (isMain: MainTC[A] {type E = _ E}).TC

How to combine type parameter bounds and functors using Cats?

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]"
}

Avoid code duplication using duck typing in scala

I am currently coding in scala and I consider my self a newbie.
I have 3 classes that are out of my control, that means that I can't change them.
class P
class A {
def m(p: P): A = { println("A.m"); this }
}
class B {
def m(p: P): B = { println("B.m"); this }
}
This is a simplified example the actual code is more complicated and classes A, B have many other similar methods.
I need to call method m for instances of classes A, B
The obvious solution is:
def fill(ab: AnyRef, p: P): Unit = {
ab match {
case a: A => a.m(p)
case b: B => b.m(p)
}
}
but that involves code duplication. I tried to solve it with duck typing and so far my best take on the subject is this:
type WithM[T] = { def m(p: P): T }
def fill[S, T <: WithM[S]](ab: T, p: P): S =
ab.m(p)
fill(new A, new P)
but I get type inference errors like:
Error:(18, 5) inferred type arguments [Nothing,A] do not conform to method fill's type parameter bounds [S,T <: Test.WithM[S]]
fill(new A, new P)
^
Can this problem be solved in an elegant way with minimal magic?
You've got a few options. One is to provide the type parameters explicitly:
scala> fill[A, A](new A, new P)
A.m
res1: A = A#4beb8b21
If the m method always returns a value of the type that it's defined on, you can help out the type inference by encoding that fact in your fill:
scala> def fill[T <: WithM[T]](o: T, p: P): T = o.m(p)
fill: [T <: WithM[T]](o: T, p: P)T
scala> fill(new A, new P)
A.m
res2: A = A#5f9940d4
You can also skip the type alias:
scala> def fill[S](o: { def m(o: P): S }, p: P): S = o.m(p)
fill: [S](o: AnyRef{def m(o: P): S}, p: P)S
scala> fill(new A, new P)
A.m
res3: A = A#3388156e
I'd strongly suggest using a type class, though—it's a little bit of syntactic overhead but much cleaner:
trait HasM[T] {
type Out
def apply(t: T, p: P): Out
}
object HasM {
type Aux[T, Out0] = HasM[T] { type Out = Out0 }
implicit def AHasM: Aux[A, A] = new HasM[A] {
type Out = A
def apply(t: A, p: P): A = t.m(p)
}
implicit def BHasM: Aux[B, B] = new HasM[B] {
type Out = B
def apply(t: B, p: P): B = t.m(p)
}
}
def fill[T](t: T, p: P)(implicit hm: HasM[T]): hm.Out = hm(t, p)
And then:
scala> fill(new A, new P)
A.m
res4: A = A#74e92aa9
scala> fill(new B, new P)
B.m
res5: B = B#1ea35068
No reflective access and you're using a widely-understood idiom.
You can use a typeclass, but honestly in this case I would just pattern match if there's really not common supertype of A and B.
trait POps[T] {
def m(t: T, p: P): T
}
object POps {
def apply[T : POps] = implicitly[POps[T]]
}
object A {
implicit val aPops: POps[A] = new POps[A] {
def m(t: A, p: P) = t.m(p)
}
}
object B {
implicit val bPops: POps[B] = new POps[B] {
def m(t: B, p: P) = t.m(p)
}
}
def fill[M : POps](o: M, p: P): Unit = {
POps[M].m(o, p)
}
If there are really only two then just use pattern matching.

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") }