Skip to content

Instantly share code, notes, and snippets.

@teldosas
Forked from limansky/Linear.scala
Last active January 14, 2017 14:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save teldosas/8baca56ebda4eb8033b2d60bd73d4199 to your computer and use it in GitHub Desktop.
Save teldosas/8baca56ebda4eb8033b2d60bd73d4199 to your computer and use it in GitHub Desktop.
Linear type class
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)
}
}
@limansky
Copy link

Looks like UnZip can be simplified:

object UnZip {
  implicit def unzip[S, T]: UnZip[FieldType[S, T], T] = new UnZip[FieldType[S, T], T] {
    def apply(f: FieldType[S, T]) = f
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment