2016-03-07 19 views
9

Aşağıdaki durum var, iki tür MA ve MB verilen, her ikisi de bir Applicative sahip değil, aynı zamanda her ikisi de aynı temel şekle sahip olduklarını kanıtlamak mümkün olmak istiyorum.Özdeş tür sınıflarını ayıklamak için Unapply kullanın

type UnapplyM[TC[_[_]], MA, M0[_]] = Unapply[TC, MA]{ type M[X] = M0[X] } 

implicit def thing[MA, MB, M[_]](implicit un: UnapplyM[Applicative,MA,M], un2: UnapplyM[Applicative,MB,M]) = ... 

ama Benzer şeyler Unapply ve işin A tip param bir tip projeksiyonu ile yapılabilir (yani bu işe yaramaz.) Iraksak implicits içine yayınlanmaya devam: Ben aşağıdakileri yaparak çalıştı.

Bu iki türü almanın ve aslında aynı tür sınıf örneği tarafından desteklendiklerini kanıtlamanın bir yolu var mı?

cevap

9

Tam bir cevabın çok uzun bir hikaye olacağını söyleyerek başlayacağım ve geçen yazın büyük bir bölümünü in a blog post söyledim, bu yüzden burada bazı ayrıntıları gözden geçireceğim ve Cats için thing'un bir çalışma uygulaması.

Bir başka tanıtım notu: bu makine artık Scalaz'da ve my pull request numaralı telefondan some of the "review"'da var. Kedilere sevindiğim için pek çok neden var. :) Hatta burada motive denemez tamamen opak tip sınıf için

İlk: Kediler anda birine sahip görünmüyor çünkü

case class SingletonOf[T, U <: { type A; type M[_] }](
    widen: T { type A = U#A; type M[x] = U#M[x] } 
) 

object SingletonOf { 
    implicit def mkSingletonOf[T <: { type A; type M[_] }](implicit 
    t: T 
): SingletonOf[T, t.type] = SingletonOf(t) 
} 

Sonra, bir IsoFunctor tanımlayabilirsiniz :

import cats.arrow.NaturalTransformation 

trait IsoFunctor[F[_], G[_]] { 
    def to: NaturalTransformation[F, G] 
    def from: NaturalTransformation[G, F] 
} 

object IsoFunctor { 
    implicit def isoNaturalRefl[F[_]]: IsoFunctor[F, F] = new IsoFunctor[F, F] { 
    def to: NaturalTransformation[F, F] = NaturalTransformation.id[F] 
    def from: NaturalTransformation[F, F] = to 
    } 
} 

Biz yaptığımız üzere olduğun şey için IsoFunctor biraz daha basit birşey kullanabilirsiniz, ama buna ben Scalaz kullanılan ne güzel ilkeli tip sınıfı, ve, bu yüzden buraya o çakacağım . İki Unapply örneklerini bunlara örnek olarak verilebilir bir yeni Unapply için

Sonraki: herhangi kullanışlı örneklerini vardı önce tarihsel bir yan not olarak

import cats.Unapply 

trait UnapplyProduct[TC[_[_]], MA, MB] { 
    type M[X]; type A; type B 
    def TC: TC[M] 
    type MA_ = MA 
    def _1(ma: MA): M[A] 
    def _2(mb: MB): M[B] 
} 

object UnapplyProduct { 
    implicit def unapplyProduct[ 
    TC[_[_]], MA0, MB0, 
    U1 <: { type A; type M[_] }, 
    U2 <: { type A; type M[_] } 
    ](implicit 
    sU1: SingletonOf[Unapply[TC, MA0], U1], 
    sU2: SingletonOf[Unapply[TC, MB0], U2], 
    iso: IsoFunctor[U1#M, U2#M] 
): UnapplyProduct[TC, MA0, MB0] { 
    type M[x] = U1#M[x]; type A = U1#A; type B = U2#A 
    } = new UnapplyProduct[TC, MA0, MB0] { 
    type M[x] = U1#M[x]; type A = U1#A; type B = U2#A 
    def TC = sU1.widen.TC 
    def _1(ma: MA0): M[A] = sU1.widen.subst(ma) 
    def _2(mb: MB0): M[B] = iso.from(sU2.widen.subst(mb)) 
    } 
} 

, UnapplyProduct Scalaz dört yıl süre yaşadı.

Ve şimdi yazabilir böyle bir şey: o zaman

import cats.Applicative 

def thing[MA, MB](ma: MA, mb: MB)(implicit 
    un: UnapplyProduct[Applicative, MA, MB] 
): Applicative[un.M] = un.TC 

Ve:

scala> import cats.data.Xor 
import cats.data.Xor 

scala> thing(Xor.left[String, Int]("foo"), Xor.right[String, Char]('a')) 
res0: cats.Applicative[[x]cats.data.Xor[String,x]] = [email protected] 

Ve başarıyla böyle bir bu Xor tip yıkmak için nasıl tanımlamak içine derleyici konuştum İlgili Applicative örneğini görebildiğimiz yol (bu da geri dönüyoruz).

+1

Dipnot olarak, 'SingletonOf' fikrinin% 100'ü Miles Sabin'e düşer (tabi ki): https://gist.github.com/milessabin/cadd73b7756fe4097ca0 –

+0

Ugh, gerçekten Scala'dan gerçekten nefret ediyorum. Bizi böylesine büyük uzunluklara götürüyor. – wheaties

İlgili konular