3

私は同等のものを構築したいと思います:

def applyWithHList2[A1, A2, R, L <: HList](l: L, f: Function2[A1, A2, R]): Try[R]

リスト内の値は、N で 2 つの可能な値の組み合わせを選択するようなものでl.unify、関数の呼び出しに使用できるのは最大で 1 つです。追加のタイプ情報はありません。

Failure関数を呼び出す方法がない場合、結果はwithになるはずMatchErrorです。それ以外の場合、結果は になりますTry(f(a1, a2))

私はまだ形のないことに慣れており、この問題に取り組む方法についての提案をいただければ幸いです。

4

1 に答える 1

3

おかしなことに、適切に型指定された要素が で利用できない場合、コンパイルされないバージョンを作成する方がはるかに簡単ですHList

import shapeless._, ops.hlist.Selector

def applyWithHList2[A1, A2, R, L <: HList](l: L, f: (A1, A2) => R)(implicit
  selA1: Selector[L, A1],
  selA2: Selector[L, A2]
): R = f(selA1(l), selA2(l))

Try該当するペアがない場合に実行時エラー ( 内) が本当に必要な場合は、既定のnullインスタンス トリックを使用できます。

import scala.util.{ Failure, Success, Try }

def applyWithHList2[A1, A2, R, L <: HList](l: L, f: (A1, A2) => R)(implicit
  selA1: Selector[L, A1] = null,
  selA2: Selector[L, A2] = null
): Try[R] = Option(selA1).flatMap(s1 =>
  Option(selA2).map(s2 => f(s1(l), s2(l)))
).fold[Try[R]](Failure(new MatchError()))(Success(_))

それが不快であると感じた場合 (実際にそうです)、カスタム型クラスを使用できます。

trait MaybeSelect2[L <: HList, A, B] {
  def apply(l: L): Try[(A, B)] = (
    for { a <- maybeA(l); b <- maybeB(l) } yield (a, b)
  ).fold[Try[(A, B)]](Failure(new MatchError()))(Success(_))

  def maybeA(l: L): Option[A]
  def maybeB(l: L): Option[B]
}

object MaybeSelect2 extends LowPriorityMaybeSelect2 {
  implicit def hnilMaybeSelect[A, B]: MaybeSelect2[HNil, A, B] =
    new MaybeSelect2[HNil, A, B] {
      def maybeA(l: HNil): Option[A] = None
      def maybeB(l: HNil): Option[B] = None
    }

  implicit def hconsMaybeSelect0[H, T <: HList, A](implicit
    tms: MaybeSelect2[T, A, H]
  ): MaybeSelect2[H :: T, A, H] = new MaybeSelect2[H :: T, A, H] {
    def maybeA(l: H :: T): Option[A] = tms.maybeA(l.tail)
    def maybeB(l: H :: T): Option[H] = Some(l.head)
  }

  implicit def hconsMaybeSelect1[H, T <: HList, B](implicit
    tms: MaybeSelect2[T, H, B]
  ): MaybeSelect2[H :: T, H, B] = new MaybeSelect2[H :: T, H, B] {
    def maybeA(l: H :: T): Option[H] = Some(l.head)
    def maybeB(l: H :: T): Option[B] = tms.maybeB(l.tail)
  }
}

trait LowPriorityMaybeSelect2 {
  implicit def hconsMaybeSelect2[H, T <: HList, A, B](implicit
    tms: MaybeSelect2[T, A, B]
  ): MaybeSelect2[H :: T, A, B] = new MaybeSelect2[H :: T, A, B] {
    def maybeA(l: H :: T): Option[A] = tms.maybeA(l.tail)
    def maybeB(l: H :: T): Option[B] = tms.maybeB(l.tail)
  }
}

その後:

def applyWithHList2[A1, A2, R, L <: HList](l: L, f: (A1, A2) => R)(implicit
  ms2: MaybeSelect2[L, A1, A2]
): Try[R] = ms2(l).map(Function.tupled(f))

しかし、コンパイル時の安全性を捨てるだけでも大変な作業です。

あなたの質問の前提条件としてそれを読んだので、これらのアプローチのいずれもHList、関数を適用できるのは最大でも要素のペアのみであるという制約を強制しないことに注意してください。コンパイル時に制約を強制するソリューションを作成することは間違いなく可能です (MaybeSelect2上記の実装よりも少し短い場合もあります)。

于 2016-01-18T03:21:20.043 に答える