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

+3


source to share


1 answer


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

      

+3


source







All Articles