2015-12-20 174 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類型所做的。