Update
This question is about replacing Any
with A
in step(x.flatMap((a: Any) => f(a).flatMap(g)))
. Type erasure in pattern matching seems to make this difficult.
def step[F[_], A](freeFA: Free[F,A]): Free[F,A] =
freeFA match {
case FlatMap(
FlatMap(x, f), g
) => step(x.flatMap((a: Any) => f(a).flatMap(g)))
.
.
.
}
I appreciate the points in the comments that the Free monad is irrelevant to the crux of the question. My example needed include a generic type A
and a generic type F[_]
(a higher kinded type?).
It's a pedantic question and I'm interested to know "how to get around type erasure" (How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?), even though the code compiles. I couldn't figure out how to apply TypeTags to this by myself.
The mention of static type checking is useful. Would someone explain why Any
is set to A
by static type checking and not dynamic type checking? I believed that type erasure was making static type checking impossible here, and that the compiler was retreating to dynamic type checking to resolve Any
to A
. Thank you
I have three case classes,
case class Return[F[_],A](a: A) extends Free[F, A]
case class Suspend[F[_],A](s: F[A]) extends Free[F, A]
case class FlatMap[F[_],A,B](s: Free[F, A],
f: A => Free[F, B]) extends Free[F, B]
which inherit from trait Free
:
sealed trait Free[F[_],A] {
def flatMap[B](f: A => Free[F,B]): Free[F,B] =
FlatMap(this, f)
def map[B](f: A => B): Free[F,B] =
flatMap(f.andThen(Return(_)))
}
step
, and the classes above, are part of an exercise in chapter 13 of "Functional Programming in Scala" to implement trampolining.
Because type erasure discourages type annotations within case FlatMap(FlatMap(x, f), g)
, the generic types within this case are left unspecified and become Any
when made concrete. Then, the required signature of the anonymous function given to x.flatMap
becomes Any=>Free[F,A]
. I'd like the required signature of this function to be A=>Free[F,A]
-- the true signature at runtime.
def step[F[_], A](freeFA: Free[F,A]): Free[F,A] =
freeFA match {
case FlatMap(
FlatMap(x, f), g
) => step(x.flatMap((a: Any) => f(a).flatMap(g)))
.
.
.
}
Annotating the input type of the anonymous function given to flatMap
as A
makes compilation fail,
step(x.flatMap((a: A) => f(a).flatMap(g)))
and I understand this is because A
is only a subset of Any
:
[error] found : A => fpinscala.iomonad.IO3.Free[F,A]
[error] required: Any => fpinscala.iomonad.IO3.Free[F,A]
Type erasure prevents me from narrowing down Any
to A
like so:
def step[F[_], A](freeFA: Free[F,A]): Free[F,A] =
freeFA match {
case FlatMap(
FlatMap(
x: Free[F,A],
f: Function1[A,Free[F,A]]
),
g: Function1[A,Free[F,A]]
) => step(x.flatMap((a: A) => f(a).flatMap(g)))
.
.
.
}
Annotating the case
statement this way serves no purpose other than documentation, and even causes problems, written up here: Scala: type annotations make tail recursion check fail
I can't figure out how to apply TypeTags to this situation.
How can I annotate this case
statement to knock down Any
to A
? Thanks!!