Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Code from my talk on representing polymorphic function values using type classes at the Scala eXchange ... full blog post to follow on http://www.chuusai.com/blog.

View conversions.scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
object Tuples {
import HLists._
 
implicit def tuple1ToHList[A](t : Product1[A]) = new { def hlisted : A :: HNil = t._1 :: HNil }
implicit def tuple2ToHList[A, B](t : Product2[A, B]) = new { def hlisted : A :: B :: HNil = t._1 :: t._2 :: HNil }
implicit def tuple3ToHList[A, B, C](t : Product3[A, B, C]) = new { def hlisted : A :: B :: C :: HNil = t._1 :: t._2 :: t._3 :: HNil }
 
implicit def hListToTuple1[A](h : A :: HNil) = new { def tupled : Tuple1[A] = Tuple1(h.head) }
implicit def hListToTuple2[A, B](h : A :: B :: HNil) = new { def tupled : (A, B) = (h.head, h.tail.head) }
implicit def hListToTuple3[A, B, C](h : A :: B :: C :: HNil) = new { def tupled : (A, B, C) = (h.head, h.tail.head, h.tail.tail.head) }
}
 
object Functions {
import HLists._
 
implicit def fnToHListFn1[A, T](f : A => T) = (h : A :: HNil) => f(h.head)
implicit def fnToHListFn2[A, B, T](f : (A, B) => T) = (h : A :: B :: HNil) => (f curried)(h.head)(h.tail.head)
implicit def fnToHListFn3[A, B, C, T](f : (A, B, C) => T) = (h : A :: B :: C :: HNil) => (f curried)(h.head)(h.tail.head)(h.tail.tail.head)
implicit def hlistFnToFn1[A, T](hf : A :: HNil => T) = (a : A) => hf(a :: HNil)
implicit def hlistFnToFn2[A, B, T](hf : A :: B :: HNil => T) = (a : A, b : B) => hf(a :: b :: HNil)
implicit def hlistFnToFn3[A, B, C, T](hf : A :: B :: C :: HNil => T) = (a : A, b : B, c : C) => hf(a :: b :: c :: HNil)
}
View conversions.scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
object HLists {
sealed trait HList
 
final case class HCons[H, T <: HList](head : H, tail : T) extends HList {
def ::[T](v : T) = HCons(v, this)
override def toString = head+" :: "+tail.toString
}
 
sealed class HNil extends HList {
def ::[T](v : T) = HCons(v, this)
override def toString = "HNil"
}
case object HNil extends HNil
type ::[H, T <: HList] = HCons[H, T]
val :: = HCons
}
 
object MapFn {
import PolyFun._
import HLists._
 
trait Mapper[F <: Trans, In, Out] {
def map(t : In) : Out
}
implicit def hnilMapper[F <: Trans] = new Mapper[F, HNil, HNil] {
def map(l : HNil) = HNil
}
implicit def hlistMapper[F <: Trans, InH, OutH, InT <: HList, OutT <: HList](implicit fh : F#λ[InH, OutH], mt : Mapper[F, InT, OutT]) = new Mapper[F, InH :: InT, OutH :: OutT] {
def map(l : InH :: InT) = HCons(fh(l.head), mt.map(l.tail))
}
 
trait PartialMap[F <: Trans] {
def apply[In <: HList, Out <: HList](in : In)(implicit mapper : Mapper[F, In, Out]) : Out = mapper.map(in)
}
def map[F <: Trans] = new PartialMap[F] {}
}
 
object FoldFn {
import PolyFun._
import HLists._
trait FoldLeft[F <: Trans, In, R] {
def foldLeft(l : In, acc : R, op : (R, R) => R) : R
}
implicit def hlistFoldLeft[F <: Trans, InH, InT <: HList, R](implicit fh : F#λ[InH, R], ft : FoldLeft[F, InT, R]) = new FoldLeft[F, InH :: InT, R] {
def foldLeft(l : InH :: InT, acc : R, op : (R, R) => R) = ft.foldLeft(l.tail, op(fh(l.head), acc), op)
}
 
implicit def hnilFoldLeft[F <: Trans, R] = new FoldLeft[F, HNil, R] {
def foldLeft(l : HNil, acc : R, op : (R, R) => R) : R = acc
}
 
trait PartialFoldLeft[F <: Trans] {
def apply[In <: HList, R](in : In)(z : R)(op : (R, R) => R)(implicit folder : FoldLeft[F, In, R]) : R = folder.foldLeft(in, z, op)
}
def foldLeft[F <: Trans] = new PartialFoldLeft[F] {}
}
 
object LiftO {
import GetFn._
import IsDefinedFn._
import HLists._
import MapFn._
import FoldFn._
import Functions._
def liftO[In <: HList, Out <: HList, R](f : Out => R)(implicit mapper : Mapper[Get, In, Out], folder : FoldLeft[IsDefined, In, Boolean]) =
(i : In) => if(foldLeft[IsDefined](i)(true)(_ & _)) Option(f(map[Get](i))) else None
 
val sumO = liftO((_ : Int) + (_ : Int))
val prodO = liftO((_ : Int) * (_ : Int) * (_ : Int))
def main(args : Array[String]) {
val s1 = sumO(Some(1), Some(2))
println(s1)
 
val s2 = sumO(Some(1), None)
println(s2)
val s3 = sumO(None, Some(2))
println(s3)
val s4 = sumO(None, None)
println(s4)
val p1 = prodO(Some(2), Some(3), Some(4))
println(p1)
 
val p2 = prodO(Some(2), None, Some(4))
println(p2)
}
}
 
object TestHList {
import IncFn._
import GetFn._
import IsDefinedFn._
import HLists._
import MapFn._
import FoldFn._
 
def main(args : Array[String]) {
val i1 = inc(23)
println(i1)
val i2 = inc("foo")
println(i2)
type ISII = Int :: String :: Int :: Int :: HNil
val l1 : ISII = 1 :: "foo" :: 2 :: 3 :: HNil
println(l1)
 
val l2 : ISII = map[Inc](l1)
println(l2)
type OIOS = Option[Int] :: Option[String] :: HNil
type IS = Int :: String :: HNil
val l3 = Option(1) :: Option("foo") :: HNil
val l4 : IS = map[Get](l3)
println(l3)
println(l4)
val l5 : IS = map[Get](l3)
println(l5)
 
type OIODOBOSOI = Option[Int] :: Option[Double] :: Option[Boolean] :: Option[String] :: Option[Int] :: HNil
type IDBSI = Int :: Double :: Boolean :: String :: Int :: HNil
type BBBBB = Boolean :: Boolean :: Boolean :: Boolean :: Boolean :: HNil
val l6 : OIODOBOSOI = Option(1) :: Option(1.0) :: Option(false) :: Option("foo") :: Option(2) :: HNil
val l7 : OIODOBOSOI = Option(1) :: Option(1.0) :: (None : Option[Boolean]) :: Option("foo") :: Option(2) :: HNil
 
val l8 : IDBSI = map[Get](l6)
println(l8)
 
val l9 : BBBBB = map[IsDefined](l6)
println(l9)
val l10 : BBBBB = map[IsDefined](l7)
println(l10)
 
val b1 = foldLeft[IsDefined](l6)(true)(_ & _)
println(b1)
 
val b2 = foldLeft[IsDefined](l7)(true)(_ & _)
println(b2)
}
}
View conversions.scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
object PolyFun {
 
type Trans = {
type λ[T, R] <: (T => R)
}
trait TransCase[F, T, R] extends (T => R) {
val f : T => R
def apply(t : T) : R = f(t)
}
trait PTrans[F] {
type λ[T, R] = TransCase[F, T, R]
}
}
object Uses {
import PolyFun._
def useTrans1[F <: Trans](implicit fi : F#λ[Int, Int], fs : F#λ[String, String]) = (fi(23), fs("foo"))
trait PartialUseTransPoly1[F <: Trans] {
def apply[T, U](t : T, u : U)(implicit ft : F#λ[T, T], fu : F#λ[U, U]) = (ft(t), fu(u))
}
def useTransPoly1[F <: Trans] = new PartialUseTransPoly1[F] {}
def useTrans2[F <: Trans](implicit fi : F#λ[Int, Int], fs : F#λ[String, Int]) = (fi(23), fs("foo"))
trait PartialUseTransPoly2[F <: Trans] {
def apply[T, U](t : T, u : U)(implicit ft : F#λ[T, Int], fu : F#λ[U, Int]) = (ft(t), fu(u))
}
def useTransPoly2[F <: Trans] = new PartialUseTransPoly2[F] {}
}
 
object IncFn {
import PolyFun._
 
class Inc extends PTrans[Inc]
object Inc {
def apply[T](f0 : T => T) = new TransCase[Inc, T, T] { val f = f0 }
}
implicit def incInt = Inc[Int](_+1)
implicit def incString = Inc[String](_+"*")
def inc[T](t : T)(implicit f : TransCase[Inc, T, T]) = f(t)
 
inc(23)
inc("foo")
}
 
object TwiceFn {
import PolyFun._
 
class Twice extends PTrans[Twice]
object Twice {
def apply[T](f0 : T => T) = new TransCase[Twice, T, T] { val f = f0 }
}
implicit def twiceInt = Twice[Int](_*2)
implicit def twiceString = Twice[String](s => s+s)
def twice[T](t : T)(implicit f : TransCase[Twice, T, T]) = f(t)
 
twice(23)
twice("foo")
}
 
object SizeFn {
import PolyFun._
class Size extends PTrans[Size]
object Size {
def apply[T](f0 : T => Int) = new TransCase[Size, T, Int] { val f = f0 }
}
implicit def sizeInt = Size[Int](identity)
implicit def sizeString = Size[String](_.length)
def size[T](t : T)(implicit f : TransCase[Size, T, Int]) = f(t)
 
size(23)
size("foo")
}
 
object GetFn {
import PolyFun._
class Get extends PTrans[Get]
object Get {
def apply[T](f0 : Option[T] => T) = new TransCase[Get, Option[T], T] { val f = f0 }
}
implicit def getDflt[T] = Get[T](_.get)
def get[T](t : Option[T])(implicit f : TransCase[Get, Option[T], T]) = f(t)
 
get(Option(23))
get(Option("foo"))
}
 
object IsDefinedFn {
import PolyFun._
class IsDefined extends PTrans[IsDefined]
object IsDefined {
def apply[T](f0 : Option[T] => Boolean) = new TransCase[IsDefined, Option[T], Boolean] { val f = f0 }
}
implicit def idDefinedDflt[T] = IsDefined[T](_.isDefined)
 
def isDefined[T](t : Option[T])(implicit f : TransCase[IsDefined, Option[T], Boolean]) = f(t)
 
isDefined(Option(23))
isDefined(Option("foo"))
}
 
object TestPolyFun {
import Uses._
import IncFn._
import SizeFn._
def main(args : Array[String]) {
val p1 = useTrans1[Inc]
println(p1)
val p2 = useTransPoly1[Inc](23, "foo")
println(p2)
val p3 = useTransPoly1[Inc]("foo", 23)
println(p3)
val p4 = useTrans2[Size]
println(p4)
val p5 = useTransPoly2[Size](23, "foo")
println(p5)
val p6 = useTransPoly2[Size]("foo", 23)
println(p6)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.