我遇到了很多用例,在我还使用类型参数范围的情况下,尝试结束编写Functor
,Applicative
,Monad
等实例的情况。
例如...
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] = {
???
}
...当我尝试对此进行编译时,会出现以下错误。
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
如何为我也使用类型参数的上下文编写Functor
,Applicative
,Monad
等实例?可能吗有没有更合适的前进方向?
答案 0 :(得分:0)
(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:
<: UB
on type parameterTC
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]"
}