I am dipping my toes in higher kinded types, exploring a very basic Scala example:
trait Mappable[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
object Mappable {
implicit object MappableOption extends Mappable[Option] {
def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
}
implicit object MappableSeq extends Mappable[Seq] {
def map[A, B](fa: Seq[A])(f: A => B): Seq[B] = fa.map(f)
}
}
def bananaTuple[F[_], T](f: F[T])(implicit F: Mappable[F]): F[(String, T)] =
F.map(f)(("banana", _))
This works:
bananaTuple(Option(42)) // Some((banana,42))
bananaTuple(Seq(42)) // List((banana,42))
But this does not compile:
bananaTuple(Some(42))
bananaTuple(List(42))
The compile errors I get:
could not find implicit value for parameter F: ch.netzwerg.hkt.HigherKindedTypes.Mappable[Some] bananaTuple(Some(42))
not enough arguments for method bananaTuple: (implicit F: ch.netzwerg.hkt.HigherKindedTypes.Mappable[Some])Some[(String, Int)]. Unspecified value parameter F. bananaTuple(Some(42))
How can I bring variance into the game?
We can make this work with a little more parameteric polymorphism:
object MappableExample {
trait Mappable[F[_]] {
type Res[_]
def map[A, B](f: A => B)(c: F[A]): Res[B]
}
implicit def seqMappable[C[X] <: Seq[X]] = new Mappable[C] {
type Res[X] = Seq[X]
override def map[A, B](f:A => B)(c: C[A]): Seq[B] = c.map(f)
}
implicit def optionMappable[C[X] <: Option[X]]: Mappable[C] = new Mappable[C] {
type Res[X] = Option[X]
override def map[A, B](f: A => B)(c: C[A]): Option[B] = c.map(f)
}
def map[A, B, C[_]](xs: C[A])(f: A => B)(implicit mappable: Mappable[C]): mappable.Res[B] = {
mappable.map(f)(xs)
}
def main(args: Array[String]): Unit = {
println(map(List(1,2,3))(("banana", _)))
println(map(Some(1))(("banana", _)))
}
}
Yields:
List((banana,1), (banana,2), (banana,3))
Some((banana,1))
The compiler now infers Some as Mappable[Some]#Res[Int] and Mappable[List]#Res[Int] which is quite ugly. One would expect the compiler to actually be able to infer the right type without needing for any co/contravariance on the Mappable trait, which we can't do since we're using it in an invariant position.
Subtype polymorphism allows us to pass values of a certain type or any of its subtypes to a method. If a method takes a value of type Fruit, we can also pass an Apple inside (an apple is a fruit after all). So if you want to be able to pass a Mappable.MappableOption to your bananaTuple method, you have to make that MappableOption a subtype of MappableSome (since the type of your first parameter of bananaTuple dictates the implicit one). This means that you want your Mappable contravariant (if Some <: Option, then Mappable[Some] >: Mappable[Option]).
But you cannot have Mappable[F[_]] contravariant in F because F appears in covariant position of map (as a function parameter). Note that F also appears in contravariant position of map (as a return value).
If you manage to make Mappable[F[_]] contravariant in F, it should work, but I'm not sure if making it contravariant makes sense. That is, if you want a subtype relationship such as e.g. Apple <: Fruit to result in Mappable[Apple] >: Mappable[Fruit] (this would not compile since Apple and Fruit are not type constructors, but I'm just using simple types to make a point here).
Making a type contravariant in its type and solving the problem of contravariant type appearing in covariant position is a common problem and perhaps it's better if you search for it elsewhere (here is one example). I still think that it's better to provide an implicit object for every type you want to use, that is, to provide separate implicit objects for e.g. Seq and List.
Related
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.
I'm reading about higher kinded types in Scala and I can't wrap my head around the use of the underscore.
For example:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B) : F[B]
}
val listFunctor = new Functor[List] {
override def map[A, B](fa: List[A])(f: A => B) = fa.map(f)
}
listFunctor.map(List(1,2,3))(_ + 3)
If I use a parametrised type A in the trait, I get the same result:
trait Functor2[F[A]] {
def map[A, B](fa: F[A])(f: A => B) : F[B]
}
val listFunctor2 = new Functor2[List] {
override def map[A, B](fa: List[A])(f: A => B) = fa.map(f)
}
listFunctor2.map(List(1,2,3))(_ + 3)
Is there a significant difference between the two examples?
There's no difference between those two ways to express the fact that Functor2 is parametrized over a type constructor. If you notice, in the latter case, A is just a placeholder, as it hasn't been declared elsewhere.
I generally prefer to use the F[_] syntax as it clarifies we want a type constructor and we don't have accidental overlapping in naming between the placeholder and types as referred within the class: in the latter case, even though they happen to refer to the same type parameter, there is no enforced constraint between the A in the constructor signature and the A in the map method signature, and this can also lead to some confusion regarding the nature of the two A and how they are related to each other.
In scala, I have a container type with an error case and held type:
case class Extract[E, A](runView: View => EitherT[Future, E, (A, View)]) {...}
Which I intend to use as a sort of asynchronous state monad. I have implemented all of the map, flatMap utility methods for this.
I now want to mark this type as being a member of the Monad type class in scalaz, and I'm struggling to work out the syntax for specifying that the type parameter I want the type monadic over is the A type, since Monad takes a type with a single type parameter. Below is an incorrect attempt I made.
implicit def extractInterface[E] = new Monad[Extract[E, A]] {
def point[A](a: => A): Extract[E, A] = {...}
def bind[A, B](fa: Extract[E, A])(f: (A) => Extract[E, B]): Extract[E, B] = fa.flatMap(f)
}
I have tried looking at the scalaz instances for E \/ A, but they use a ? type parameter, for which I cannot find a definition.
Is there a syntactic trick to do what I want?
You should use type lambda
implicit def extractInterface[E] = new Monad[({ type λ[A] = Extract[E, A] })#λ] {
...
}
Alternatively you can use kind-projector plugin.
implicit def extractInterface[E] = new Monad[Extract[E, ?]] {
...
}
What is the ? type?
I am trying to implement a cats Monad instance for a type that has multiple type parameters. I looked at the cats Either instance to see how it was done there. Part of the Either Monad instance code from cats is copied below:
import cats.Monad
object EitherMonad {
implicit def instance[A]: Monad[Either[A, ?]] =
new Monad[Either[A, ?]] {
def pure[B](b: B): Either[A, B] = Right(b)
def flatMap[B, C](fa: Either[A, B])(f: B => Either[A, C]): Either[A, C] =
fa.right.flatMap(f)
}
}
It fails to compile with the error: error: not found: type ?
What is the ? type and how can I use it when creating instances for my own types?
It is special syntax for so-called type lambdas that is added by the kind projector plugin.
Either[A, ?]
is a shortcut for
({type L[X] = Either[A, X]})#L
The whole code desugars to
import cats.Monad
object EitherMonad {
implicit def instance[A]: Monad[({type L[X] = Either[A, X]})#L] = new Monad[({type L[X] = Either[A, X]})#L] {
def pure[B](b: B): Either[A, B] = Right(b)
def flatMap[B, C](fa: Either[A, B])(f: B => Either[A, C]): Either[A, C] =
fa.right.flatMap(f)
}
}
Type lambdas look frightening, but they are essentially a very simple concept. You have a thing that takes two type parameters, like Either[A, B]. You want to provide a monad instance for Either, but trait Monad[F[_]] takes only one type parameter. But in principle that's OK, since your monad instance is only concerned with the second (the "right") type argument anyway. A type lambda is just a way to "fix" the first type argument so you have the right shape.
If you would do the same thing at value level, you wouldn't even think about it twice. You got a function of two arguments
val f: (Int, Int) => Int = ...
And something you want to pass f to, which only takes 1 argument
def foo(x: Int => Int) = ...
The only way to make things fit is to fix one of the arguments
foo(x => f(1, x))
And that's exactly what a type lambda does at type level.
I have the following trait (simplified example)
trait F[A, M[_] <: Option[A]] {
def v: A
def f: A => M[A]
}
I want to be able to create the following trait
trait G[A] extends F[A, Some]
But this gives the following error
Error:(18, 20) type arguments [A,Some] do not conform to trait F's type parameter bounds [A,M[_] <: Option[A]]
How can I bound the M[_] parameterized type ?
Edit :
A type F[A, M[_] <: Option[_]] will work. But I actually have another function in my trait
trait F[A, M[_] <: Option[_]] {
def v: A
def f: A => M[A]
def f2: A => A = {
(a: A) => f(a).get
}
}
And in that case in f2, get doesn't return a value of type A even if f returns a M[A]
Error:(17, 20) type mismatch;
found : _$1
required: A
(a: A) => f(a).get
You can fully constrain the type of M since it doesn't really need to take type parameters:
trait F[A, M <: Option[A]] { // M no longer takes a type parameter
def v: A
def f: A => M
}
trait G[A] extends F[A, Some[A]] // Must specify M[A] since M doesn't take a type parameter
However you may want to provide some sort of mapping mechanism or something and go to some other type M[B] in which case a less constrained version would work better:
trait F[A, M[_] <: Option[_]] { // M is no longer constrained to A
def v: A
def f: A => M[A] // M is manually constrained to A here
}
trait G[A] extends F[A, Some]
UPDATE
Unfortunately your f2 function won't work. Even though we know that the types are correct, the compiler can't properly infer the type (limitations of Scala). You could add this function to G[A] and it will work as expected because M[_] has a concrete type with it now.
trait G[A] extends F[A, Some]{
def f3: A => A = a => f(a).get
}
And as a side note, you should never use Option.get, it defeats the purpose of using an Option! flatMap it or something :)