Scala: creating a higher type with some generic type
For example, I have defined a Monad Trait
as follows:
trait Monad[F[_]] {
def unit[T](a: => T): F[T]
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}
I am creating ListMonad
that implement the above interface:
class ListMonad extends Monad[List] {
override def unit[T](a: => T): List[T] = List(a)
override def flatMap[A, B](fa: List[A])(f: (A) => List[B]): List[B] = fa flatMap f
}
Now I want to check the above Monad in "General way". The first attribute of the monad is Left Identity
. This means: if we give the monad "m", the value "x" and the function "f". It must satisfy:m.(identity(x)).flatMap(f) == f(x)
So, for example, I create the following validation class to test this assumption:
case class MonadVerifier[A, F[_]](monad: Monad[F[_]])(f: A => F[A]) {
def leftIdentity(value: A): Boolean =
monad.flatMap[A, A](monad.unit(value))(f) == f(value)
}
In this code, I am meeting the error:
Type mismatch. expected: (A) => F [_] [A], actual: (A) => F [A]
I don't know in Scala how I can express it F[A]
as generic. I think if I were to define F[_]
Scala it would introduce a generic type in [_]
when called F[A]
, but it doesn't.
Please help me in this case. Thanks to
source to share
What @Dima said:
The error is that
MonadVerifier[A, F[_]](monad: Monad[F[_]])
it should be
MonadVerifier[A, F[_]](monad: Monad[F])
What the first line says is not that it F
is a monad ( F
has a view * -> *
and type values F[_]
), but F[_]
(i.e. a type constructor F
applies to any type of the correct kind) is a monad, ( F
has a view * -> (* -> *)
and type values F[_][_]
).
Expanding on this (ignore this if you like): Monad
expects its type argument to take one type argument and return a specific type. The argument Monad
is said to be of the form * -> *
("function" from specific types to specific types), and itself Monad
is of the form (* -> *) -> *
("function" from "functions" from specific types to specific types to specific types). When you say Monad[F[_]]
, you are implying that argument ( F[_]
) is of the view * -> *
because it expects a view Monad
. F[_]
is the application of a type constructor F
(kind a -> b
for some unknown types a
and b
) to any particular type (implied _
by causing the type to F
be constrained * -> k
for the unknown k
). Insofar asF[_]
also has to be * -> *
due Monad
, it restricts k = (* -> *)
, and therefore F
will be forced to have a view * -> (* -> *)
that is the version (*, *) -> *
in curry. This means it F
has two types of parameters and it is monadic in the second (for example Either
).
In the future, perhaps use context to avoid such mixes:
MonadVerifier[A, F[_]: Monad] // no params needed
source to share