Created
January 12, 2017 09:23
-
-
Save limansky/072fc59ae55ea9bdab4135899f83f83d 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} | |
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, 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))) | |
} | |
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