I'm currently going through Scala with Cats and enjoying it a lot.
In Exercise 4.1.2 (Getting Func-y) we are tasked to implement map using the methods pure and flatMap only.
The code for reference:
import scala.language.higherKinds
trait Monad[F[_]] {
def pure[A](a: A): F[A]
def flatMap[A, B](value: F[A])(func: A => F[B]): F[B]
def map[A, B](value: F[A])(func: A => B): F[B] =
???
}
My thinking was as follows:
For the first parameter of flatmap we just pass value.
For the second parameter, we have the function func: A => B and a method pure, which, after eta expansion, has the form pure: A => F[A]. Therefore, we compose pure with func, i.e. we pass pure _ compose func, where pure _ eta expands pure.
map would then look like this:
def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)(pure _ compose func)
However, this didn't work and produced the following error:
[error] 7:35: type mismatch;
[error] A => B|scala.Nothing
[error] flatMap(value)(pure _ compose func)
[error] ^
[info] A => B <: ? => Nothing?
[info] false
[error] 6:30: parameter value func in method map is never used
[error] def map[A, B](value: F[A])(func: A => B): F[B] =
[error] ^
[error] two errors found
[error] (Compile / compileIncremental) Compilation failed
To my surprise, using func andThen pure for the second parameter does compile.
map defined like this compiles:
def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)(func andThen pure)
I'm surprised because I assumed that for two functions f: A => B and g: B => C, the following would hold:
f andThen g is equivalent to a => g(f(a)) and
g compose f is equivalent to a => g(f(a)),
therefore f andThen g and g compose f are equivalent.
What's the reason that this doesn't hold in general and in this example?
I used scala version 2.13.8 above.
I thought, maybe the problem relates to the eta expansion of the pure method. I found several questions relating to compose and andThen methods as well as eta expansion, but they didn't answer my question.
I found a scala 3 reference entry about Automatic Eta Expansion, so I tried my luck in scala 3.2.1:
trait Monad[F[_]]:
def pure[A](a: A): F[A]
def flatMap[A, B](value: F[A])(func: A => F[B]): F[B]
def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)(pure compose func)
Notice, how we don't need the underscore after pure anymore (it will be deprecated at some point in the future) because of the automatic eta expansion mentioned in the scala 3 reference article above.
However, this also throws an error:
-- [E007] Type Mismatch Error: --------------------------------------------------------
7 | flatMap(value)(pure compose func)
| ^^^^^^^^^^^^^^^^^
| Found: A => F[Any]
| Required: A => F[B]
|
| where: F is a type in trait Monad with bounds <: [_] =>> Any
(In the where clause, I don't understand what kind of upper bound [_] =>> Any should be.)
But, again, map using func andThen pure compiles.
Based on the error message, I now believe that the compiler can somehow not infer the correct type because... of the type parameters? I don't know.
Sometimes eta-expansion is sometimes confusing for the compiler and you have to clarify things yourself.
In Scala 2 I managed to make your code compile with:
def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)((pure[B](_)).compose(func))
because method _ doesn't always work and method(_) is more in your face (you still have to define [B] to avoid inferring it to something silly like Any or Nothing).
In Scala 3 it works slightly better:
def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)((pure[B] _).compose(func))
or even
def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)(pure[B] compose func)
works - you only have to provide [B] explicitly so that it wont attempt to combine Nothing => F[Nothing] with A => B. Currently it cannot be avoided as compiler:
tries to infer types for pure before calling compose on eta-expanded method
since no restriction yet applies, it infers it to Nothing
only then it can infer types on .compose which takes A => B value
however it already inferred that it should be something that is ? => Nothing
so this particular problem comes from compiler not inferring whole expression at once but doing it in chunks.
Related
In Scala 3 I can define a functor for state using type lambda:
given stateFunctor[S]: Functor[[A] =>> State[S, A]] with
override def map[A, B](a: State[S, A])(fx: A => B): State[S, B] = State(a.run.andThen { case (s, a) => (s, fx(a)) })
I would expect it to work with ? or _ wildcard:
given stateFunctor[S]: Functor[State[S, ?]] with
override def map[A, B](a: State[S, A])(fx: A => B): State[S, B] = State(a.run.andThen { case (s, a) => (s, fx(a)) })
but I'm getting the following compilation error:
Type argument domain.State[S, ? <: AnyKind] does not have the same kind as its bound [_$1]
given stateFunctor[S]: Functor[State[S, ? <: AnyKind]] with
Why doesn't it work? What am I missing? I thought Scala 3 supports kind-projector syntax for type wildcards.
Scala version: 3.1.3
If you need it, here are State and Functor definitions:
case class State[S, A](run:S => (S, A)):
def exec(s:S):S = run(s)._1
def eval(s:S):A = run(s)._2
trait Functor[F[_]]:
def map[A, B](a: F[A])(fx: A => B): F[B]
? is wrong. ? is for existential type State[S, ?] (in Scala 2 it was State[S, _] aka State[S, A] forSome { type A }), not for type lambda.
_ is for type lambda (in Scala 2 they were emulated ({ type F[A] = State[S, A] })#F). So it should be State[S, _] but this is not implemented yet.
https://docs.scala-lang.org/scala3/reference/changed-features/wildcards.html
The syntax of wildcard arguments in types has changed from _ to ?
We would like to use the underscore syntax _ to stand for an anonymous type parameter, aligning it with its meaning in value parameter lists. So, just as f(_) is a shorthand for the lambda x => f(x), in the future C[_] will be a shorthand for the type lambda [X] =>> C[X].
So far you can write [A] =>> State[S, A] or use kind projector State[S, *]
scalaVersion := "3.2.1"
scalacOptions += "-Ykind-projector"
I am trying to write a Functor for Either for academic purposes in Scala. With help of higher-kinded types and type-projections, I managed to write an implementation for Either.
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
object Functor {
implicit def eitherFunctor[A] = new Functor[({type λ[α] = Either[A, α]})#λ] {
override def map[B, C](fa: Either[A, B])(f: B => C) = fa.map(f)
}
}
def mapAll[F[_], A, B](fa: F[A])(f: A => B)(implicit fe: Functor[F]): F[B] = fe.map(fa)(f)
val right: Either[String, Int] = Right(2)
mapAll(right)(_ + 2)
Now, the code above does not compile. I am not sure of the reason but the compilation error that I am getting is given below -
Error:(19, 16) type mismatch;
found : Either[String,Int]
required: ?F[?A]
Note that implicit conversions are not applicable because they are ambiguous:
both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A]
and method Ensuring in object Predef of type [A](self: A)Ensuring[A]
are possible conversion functions from Either[String,Int] to ?F[?A]
mapAll(right)(_ + 2)
Can someone point what I am not doing right in the code above?
PS: Please do not suggest me to use kind-projector.
You've just been bitten by SI-2712. If you're using Scala >= 2.12.2 just add this line to your build.sbt:
scalacOptions += "-Ypartial-unification"
For other Scala versions you can use this plugin.
Either[+A, +B] is expecting two type parameters(as #Ziyang Liu said), so for your example actually need BiFunctor not Functor, BiFunctor accept two functors and bound the two types.
there is a Bifunctor from Scalaz
trait Bifunctor[F[_, _]] { self =>
////
/** `map` over both type parameters. */
def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]
So you can use this Bifunctor like:
Bifunctor[Either].bimap(Right(1): Either[String, Int])(_.toUpperCase, _ + 1).println
Hope it's helpful for you.
As others said, what the compiler is trying to tell you is that the shapes of your types don't match. When you require an F[_], you're requiring a type constructor with a single type parameter, which Either[A, B] doesn't satisfy.
What we need to do is apply a type lambda when applying mapAll, same as we did when we created the instance of the Either functor:
val right: Either[String, Int] = Right(2)
mapAll[({type λ[α]=Either[String, α]})#λ, Int, Int](right)(_ + 2)
We've now squeezed in String and fixed it as the first argument, allowing the type projected type to only need to satisfy our alpha, and now the shapes match.
Of course, we can also use a type alias which would free us from specifying any additional type information when applying mapAll:
type MyEither[A] = Either[String, A]
val right: MyEither[Int] = Right(2)
mapAll(right)(_ + 2)
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.
The following bind(>>=) code, in Haskell, does not compile:
ghci> [[1]] >>= Just
<interactive>:38:11:
Couldn't match type ‘Maybe’ with ‘[]’
Expected type: [t] -> [[t]]
Actual type: [t] -> Maybe [t]
In the second argument of ‘(>>=)’, namely ‘Just’
In the expression: [[1]] >>= Just
But, in Scala, it does actually compile and run:
scala> List( List(1) ).flatMap(x => Some(x) )
res1: List[List[Int]] = List(List(1))
Haskell's >>= signature is:
>>= :: Monad m => m a -> (a -> m b) -> m b
So, in [[1]] >>= f, f's type should be: a -> [b].
Why does the Scala code compile?
As #chi explained Scala's flatMap is more general than the Haskell's >>=. The full signature from the Scala docs is:
final def flatMap[B, That](f: (A) ⇒ GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
This implicit isn't relevant for this specific problem, so we could as well use the simpler definition:
final def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]
There is only one Problem, Option is no subclass of GenTraversableOnce, here an implicit conversion comes in. Scala defines an implicit conversion from Option to Iterable which is a subclass of Traversable which is a subclass of GenTraversableOnce.
implicit def option2Iterable[A](xo: Option[A]): Iterable[A]
The implicit is defined in the companion object of Option.
A simpler way to see the implicit at work is to assign a Option to an Iterable val:
scala> val i:Iterable[Int] = Some(1)
i: Iterable[Int] = List(1)
Scala uses some defaulting rules, to select List as the implementation of Iterable.
The fact that you can combine different subtypes of TraversableOnce with monad operations comes from the implicit class MonadOps:
implicit class MonadOps[+A](trav: TraversableOnce[A]) {
def map[B](f: A => B): TraversableOnce[B] = trav.toIterator map f
def flatMap[B](f: A => GenTraversableOnce[B]): TraversableOnce[B] = trav.toIterator flatMap f
def withFilter(p: A => Boolean) = trav.toIterator filter p
def filter(p: A => Boolean): TraversableOnce[A] = withFilter(p)
}
This enhances every TraversableOnce with the methods above. The subtypes are free to define more efficient versions on there own, these will shadow the implicit definitions. This is the case for List.
Quoting from the Scala reference for List
final def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]
So, flatMap is more general than Haskell's (>>=), since it only requires the mapped function f to generate a traversable type, not necessarily a List.
When I write a function like def foo[A,B], what exactly does the [A,B] mean? I know it's a Polymorphic Method; but when do you use foo [A] versus foo [A,B]?
Here's an example where I don't understand the difference. This function compiles:
def map[B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
Whereas this one doesn't compile. I don't understand why the A isn't required, after all A is referenced by the f: A => B:
def map[A,B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
[error] ..../Stream.scala:61: type mismatch;
[error] found : h.type (with underlying type A)
[error] required: A
[error] foldRight(empty[B])((h,t) => cons(f(h), t))
(this is from one of the FP in Scala exercises)
Addendum
After reading the answers I'm adding some context, to help future readers. The function is defined inside a trait:
trait Stream[+A] {
...
def map[B](f: A => B):Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
...
}
So the error was being caused by type shadowing, but see #acjay's excellent answer below.
Googling scala type shadowing doesn't result in a direct definition in any of the scala docs, which is interesting because as #travisbrown says below, it's "one of the most common sources of beginner confusion I've seen". There is a discussion here: Why does Scala support shadow variables?
In the first example, there's only one type parameter because that's not a function in isolation, it's a method in class Stream[A], which declares the first type parameter. Approximately like so:
class Stream[A] {
// ...
def map[B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
// ...
}
So you get the A from the surrounding class scope. Suppose instead that you made map a method on the companion object instead. In this case, the companion object has no type parameter, so you have to define both parameters on the method:
class Stream[A] {
// ... methods, with foldRight, but no `map`
}
object Stream {
// ...
def map[A, B](stream: Stream[A])(f: A => B): Stream[B] =
stream.foldRight(empty[B])((h,t) => cons(f(h), t))
// ...
}
This second option would be used slightly differently. You would say Stream.map(myStream)(myMappingFunction) instead of myStream.map(myMappingFunction). Both options are perfectly valid, but it's probably more idiomatic to put the method in the class.
So, to answer your question, you use multiple type parameters on a method when two or more of the arguments and/or return type need to be generic. You might also use two type parameters for classes as well, like (disregarding variance):
Type Map[A, B] - A is the key type and B is the value type
Type Tuple2[A, B] (better known as (A, B)) - A is the type of the 1st element, B is the type of the 2nd element
Type Function1[A, B] (better known as A => B) - A is the argument type, B is the return type
...and so on.