2015-12-20 33 views
5

Próbuję zaimplementować instancję koty Monad dla typu, który ma wiele parametrów typów. Przyjrzałem się instancji koty Either, aby zobaczyć, jak to się stało. Część kodu EitherMonad przykład z kotami jest kopiowany poniżej:Co to jest? rodzaj?

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

To nie skompilować z błędem: error: not found: type ?

Jaki jest typ ? i jak można go używać podczas tworzenia instancji dla własnej typy?

+1

'?' Jest prawidłowym symbolem, w tym przypadku jest podobne do 'A'. –

Odpowiedz

8

Jest to specjalna składnia dla tak zwanych lambd, które są dodawane przez kind projector plugin.

Either[A, ?] 

jest skrótem dla

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

Cały kod desugars do

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

Rodzaj lambdas wyglądać przerażające, ale są one w zasadzie bardzo prosta koncepcja. Masz coś, co wymaga dwóch parametrów, takich jak Either[A, B]. Jeśli chcesz podać instancję monady, ale trait Monad[F[_]] przyjmuje tylko jeden typ parametru. Ale w zasadzie to jest w porządku, ponieważ twoja monadowa instancja dotyczy tylko drugiego ("prawego") argumentu typu. Typ lambda jest po prostu sposobem na "naprawienie" pierwszego argumentu typu, abyś miał właściwy kształt.

Jeśli zrobiłbyś to samo na poziomie wartości, nie pomyślałbyś o tym nawet dwa razy. Masz funkcją dwóch argumentów

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

i coś chcesz przekazać f, który trwa tylko 1 argumentu

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

Jedynym sposobem, aby rzeczy Fit to naprawić jeden z argumentów

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

I to jest dokładnie to, co typ lambda robi na poziomie typu.