Skip to content

Instantly share code, notes, and snippets.

@travisbrown
Last active December 14, 2015 17:49
Show Gist options
  • Save travisbrown/5124684 to your computer and use it in GitHub Desktop.
Save travisbrown/5124684 to your computer and use it in GitHub Desktop.
In response to a question by Eli Bishop on the Shapeless mailing list.
// I'll assume you have something like the following:
import shapeless._
val fs = ((i: Int) => "a" * i) :: ((i: Int) => i + 42) :: HNil
val x = 3
// And you want this:
val result = "aaa" :: 45 :: HNil
// The simplest way would be to use `mapConst` and `zipApply`:
fs zipApply (fs mapConst x)
// You could also define a new type class:
trait ApplyAll[A, L <: HList, Out <: HList] {
def apply(a: A, l: L): Out
}
object ApplyAll {
implicit def hnilApplyAll[A] = new ApplyAll[A, HNil, HNil] {
def apply(a: A, l: HNil) = HNil
}
implicit def hlistApplyAll[A, R, L <: HList, O <: HList](
implicit aa: ApplyAll[A, L, O]
) = new ApplyAll[A, (A => R) :: L, R :: O] {
def apply(a: A, l: (A => R) :: L) = l.head(a) :: aa(a, l.tail)
}
}
implicit def applyAllTo[A, L <: HList, O <: HList](a: A)(l: L)(
implicit aa: ApplyAll[A, L, O]
) = aa(a, l)
// Now you can write:
applyAllTo(x)(fs)
// And get the following:
// res0: shapeless.::[String,shapeless.::[Int,shapeless.HNil]] = aaa :: 45 :: HNil
// Alternatively, if you have a fill method for `HList` (see my macro-based example below),
// you could use the existing `ZipApply` type class:
import HListExtras._
fs zipApply fill[Nat._2, Int](x)
// For the same result:
// res1: shapeless.::[String,shapeless.::[Int,shapeless.HNil]] = aaa :: 45 :: HNil
import scala.language.experimental.macros
import scala.reflect.macros.Context
object HListExtras {
def natTypeToInt(c: Context)(t: c.universe.Type): Int = {
import c.universe._
if (t =:= c.weakTypeOf[Nat._0]) 0 else {
val pred = t.baseType(typeOf[Succ[_]].typeSymbol) match {
case TypeRef(_, _, List(p)) => p
case _ => c.abort(c.enclosingPosition, "Can't convert this Nat to an integer.")
}
natTypeToInt(c)(pred) + 1
}
}
def fill[N <: Nat, A](a: A) = macro fill_impl[N, A]
def fill_impl[N <: Nat: c.WeakTypeTag, A](c: Context)(a: c.Expr[A]) =
(0 until natTypeToInt(c)(c.weakTypeOf[N])).foldLeft[c.Expr[HList]](
c.universe.reify(HNil: HNil)
) {
case (l, _) => c.universe.reify(a.splice :: l.splice)
}
}
@travisbrown
Copy link
Author

The original formulation of the question is here.

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