2015-12-20 156 views
5

我正在尝试为具有多个类型参数的类型实现一个cat Monad实例。我看着猫的实例,看看它是如何完成的。从猫EitherMonad实例代码的一部分复制如下:什么是?类型?

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) 
    } 
} 

它失败,错误编译:error: not found: type ?

什么是?型,我怎么能创造我自己的情况下,当使用类型?

+1

'?'是一个有效的符号,在这种情况下它就像'A'。 –

回答

8

这是由kind projector plugin添加的所谓类型lambda的特殊语法。

Either[A, ?] 

({type L[X] = Either[A, X]})#L 

整个代码desugars一个快捷方式到

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) 
    } 
} 

类型lambda表达式看起来可怕,但它们本质上是一个非常简单的概念。你有一个需要两个类型参数的东西,比如Either[A, B]。您希望为Either提供Monad实例,但trait Monad[F[_]]只接受一个类型参数。但原则上这没关系,因为无论如何monad实例只关心第二个(“右”)类型的参数。 lambda类型只是“修复”第一个类型参数的一种方式,因此您的形状正确。

如果你在价值层面上做同样的事情,你甚至不会考虑两次。你有两个参数

val f: (Int, Int) => Int = ... 

你想传递F到,只需要1个参数

def foo(x: Int => Int) = ... 

把事情适应的唯一方法是修复的一个参数的东西的功能

foo(x => f(1, x)) 

而这正是lambda类型所做的。