Skip to content

Instantly share code, notes, and snippets.

@travisbrown
Last active February 9, 2016 03:45
Show Gist options
  • Save travisbrown/9125c0cf1c6621552fd5 to your computer and use it in GitHub Desktop.
Save travisbrown/9125c0cf1c6621552fd5 to your computer and use it in GitHub Desktop.
import scalaz._, Scalaz._, shapeless._, ops.hlist.{ RightFolder, Tupler }
// Might as well stay generic in `F` for this part.
object applicativeFolder extends Poly2 {
implicit def caseApplicative[A, B <: HList, F[_]](implicit
app: Applicative[F]
) = at[F[A], F[B]] {
(a, b) => app.ap(a)(app.map(b)(bb => (_: A) :: bb))
}
}
// It should be possible to make this part generic in `F` as well,
// but type inference makes it tricky, so we specialize to `Option`.
def sequence[T, EL <: HList, L <: HList, OL <: HList, OT](t: T)(implicit
gen: Generic.Aux[T, EL],
eq: EL =:= L,
folder: RightFolder.Aux[L, Option[HNil], applicativeFolder.type, Option[OL]],
tupler: Tupler.Aux[OL, OT]
): Option[OT] =
eq(gen.to(t)).foldRight(some(HNil: HNil))(applicativeFolder).map(tupler(_))
@travisbrown
Copy link
Author

Works like this:

scala> sequence((some(1), some('a), some("foo")))
res2: Option[(Int, Symbol, String)] = Some((1,'a,foo))

scala> sequence((some(1), some('a), none[String]))
res3: Option[(Int, Symbol, String)] = None

And won't compile if any items in the tuple don't have Option as an outer type constructor.

@AndreasKostler
Copy link

If you provide the zero element you can:

def sequence[OL <: HList, F[_], L <: HList, T]
  (l: L, z: F[T])
  (implicit folder: RightFolder.Aux[L, F[T], applicativeFolder.type, F[OL]]) = l.foldRight(z)(applicativeFolder)

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