Ответ 1
Вы были очень близки - вам просто нужно убедиться, что у вас есть лишнее доказательство того, что он просит:
def sequence[L <: HList : *->*[Option]#λ, M <: HList](l: L)(implicit
folder: RightFolder[L, Option[HNil], optionFolder.type]
) = l.foldRight(some(HNil: HNil))(optionFolder)
Или, если вы хотите что-то более общее и имеете аппликативную реализацию следующим образом:
trait Applicative[F[_]] {
def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B]
def point[A](a: => A): F[A]
def map[A, B](fa: F[A])(f: A => B): F[B] = ap(fa)(point(f))
}
implicit object optionApplicative extends Applicative[Option] {
def ap[A, B](fa: => Option[A])(f: => Option[A => B]) = f.flatMap(fa.map)
def point[A](a: => A) = Option(a)
}
Вы можете написать:
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))
}
}
def sequence[F[_]: Applicative, L <: HList: *->*[F]#λ, M <: HList](l: L)(implicit
folder: RightFolder[L, F[HNil], applicativeFolder.type]
) = l.foldRight(implicitly[Applicative[F]].point(HNil: HNil))(applicativeFolder)
И теперь вы можете перечислить списки и т.д. (при условии, что у вас есть соответствующие экземпляры).
Обновление. Обратите внимание, что в обоих случаях я опускал аннотацию типа возвращаемого значения для sequence
. Если мы вернем его, компилятор задержит:
<console>:18: error: type mismatch;
found : folder.Out
required: F[M]
Это связано с тем, что экземпляр RightFolder
переносит свой возвращаемый тип в качестве элемента абстрактного типа. Мы знаем это F[M]
в этом случае, но компилятор не заботится о том, что мы знаем.
Если мы хотим быть явным в отношении типа возвращаемого значения, мы можем вместо этого использовать экземпляр RightFolderAux
:
def sequence[F[_]: Applicative, L <: HList: *->*[F]#λ, M <: HList](l: L)(implicit
folder: RightFolderAux[L, F[HNil], applicativeFolder.type, F[M]]
): F[M] =
l.foldRight(implicitly[Applicative[F]].point(HNil: HNil))(applicativeFolder)
Обратите внимание, что RightFolderAux
имеет дополнительный параметр типа, который указывает тип возврата.