2016-03-07 8 views
9

MAMBの2種類を指定した場合、それらは両方ともApplicativeを持つだけでなく、両方とも同じ基本形状を持つことを証明できるようにしたいと考えています。私は、次のことをやってみました:を使用して同じ種類のクラスを抽出する

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]) = ... 

が、暗黙の発散に実行し続ける同様の事がUnapplyと仕事のA typeのparamの型の投影を行うことができます(すなわち、これは動作しません。)。

これは、これらの2つのタイプを受け取り、それらが実際に同じタイプのクラスインスタンスによってサポートされていることを証明できる方法ですか?

答えて

9

完全な答えは非常に長い話であろうと私は昨年の夏からこの部分の大部分をin a blog postに伝えましたので、ここでいくつかの詳細を見てみましょうCatsthingの実装が実装されています。

この機械は現在Scalazに存在し、some of the "review"にはmy pull requestが追加されています。猫は、現時点では1を持っていないようですので、私たちは、IsoFunctorを定義することができ

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

次へ:私もここにやる気にしようとはしません完全に不透明型クラスの初:)

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

私たちは、私たちがしようとしているもののためにIsoFunctorより少しシンプルなものを使用することができますが、それは素敵な節操型クラスだし、それは私がScalazで使用されるものですので、私はここでそれに固執するだろう。 2つのUnapplyのインスタンスを一緒にバンドル新しいUnapplyため

次:それは任意の有用なインスタンスを持っていた前に、歴史的な注意点として

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で4年間存在していました。

そして今、我々は書くことができます。このような何か:その後、

import cats.Applicative 

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

そして:

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] 

そして、我々は成功し、そのような中で、これらのXorタイプを打破する方法を特定するにコンパイラを話しました私たちが返す関連するApplicativeインスタンスを見ることができます。

+1

「SingletonOf」アイデアの責任の100%は、Miles Sabin(もちろん)のものです:https://gist.github.com/milessabin/cadd73b7756fe4097ca0 –

+0

ああ、私は本当にScalaを絶対に嫌う私たちはそのような長さに行きます。 – wheaties

関連する問題