-
-
Save teldosas/8baca56ebda4eb8033b2d60bd73d4199 to your computer and use it in GitHub Desktop.
Linear type class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.limansky | |
import shapeless.ops.hlist.Prepend | |
import shapeless.{::, <:!<, Generic, HList, HNil, LabelledGeneric, Lazy} | |
import shapeless.labelled.FieldType | |
trait UnZip[-F,T] { | |
def apply(f: F): T | |
} | |
object UnZip { | |
implicit def unzip[F <: FieldType[_,T],T]: UnZip[FieldType[_,T],T] = new UnZip[FieldType[_,T],T] { | |
def apply(f: FieldType[_,T]) = f | |
} | |
} | |
trait Linear[L] { | |
type Repr <: HList | |
def linear(t: L): Repr | |
} | |
trait LowPriorityLinear { | |
type Aux[T, R] = Linear[T] { type Repr = R } | |
implicit def notListLinear[T](implicit ev: T <:!< HList): Linear.Aux[T, T :: HNil] = new Linear[T] { | |
override type Repr = T :: HNil | |
override def linear(t: T): Repr = t :: HNil | |
} | |
} | |
object Linear extends LowPriorityLinear { | |
def apply[T](implicit ev: Linear[T]): Aux[T, ev.Repr] = ev | |
implicit val hnilLinear: Linear.Aux[HNil, HNil] = createLinear(_ => HNil) | |
implicit def hconsLinear[H, T <: HList, HR <: HList, TR <: HList](implicit | |
hLinear: Lazy[Linear.Aux[H, HR]], | |
tLinear: Lazy[Linear.Aux[T, TR]], | |
prepend: Prepend[HR, TR] | |
): Linear.Aux[H :: T, prepend.Out] = { | |
createLinear { case h :: t => | |
prepend(hLinear.value.linear(h), tLinear.value.linear(t)) | |
} | |
} | |
implicit def genericLinear[T <: Product, TR <: HList, R <: HList](implicit | |
gen: LabelledGeneric.Aux[T, TR], | |
lin: Lazy[Linear.Aux[TR, R]] | |
): Linear.Aux[T, R] = { | |
createLinear(t => lin.value.linear(gen.to(t))) | |
} | |
implicit def fieldLinear[F <: FieldType[_,T],T <: Product, TR <: HList, R <: HList](implicit | |
unzip: UnZip[F,T], | |
gen: LabelledGeneric.Aux[T, TR], | |
lin: Linear.Aux[TR, R] | |
): Linear.Aux[F, R] = { | |
createLinear { f => | |
val t: T = f | |
lin.linear(gen.to(t)) | |
} | |
} | |
private def createLinear[T, R <: HList](f: T => R): Linear.Aux[T, R] = new Linear[T] { | |
override type Repr = R | |
override def linear(t: T): R = f(t) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Looks like
UnZip
can be simplified: