Skip to main content
 首页 » 编程设计

scala之使用值与参数顺序不匹配的无形 HList 调用 Scala Function2

2025年05月04日80zhwl

我想构建等同于:

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

列表中的值使得在 N 中选择 l.unify 的 2 个可能的值组合,最多有一个可用于调用函数。没有其他可用的类型信息。

如果无法调用函数,结果应该是FailureMatchError。否则,结果应该是 Try(f(a1, a2))

我仍然习惯于无形,非常感谢有关如何解决此问题的建议。

请您参考如下方法:

有趣的是,如果 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 实现短一点)。