【问题标题】:Usage of enclosing generic type parameters in nested polymorphic values在嵌套多态值中使用封闭泛型类型参数
【发布时间】:2013-11-19 02:14:14
【问题描述】:

是否可以仅使用不带 TypeTags 的多态函数重写以下示例?该示例由一个类A[T] 组成,该类具有一个方法matches,当应用于A 的实例时返回true,该实例具有相同的类型参数Tfalse,如果此类型参数具有不同的值。然后将matches 映射到A[T] 的hlist l 上两次,从而生成嵌套hlist 的hlist,其中包含将l 的每个项目与其他项目匹配的结果:

import scala.reflect.runtime.universe._
import shapeless._

class A[T: TypeTag]{
  object matches extends Poly1 {
    implicit def default[U: TypeTag] = at[A[U]]{ _ => typeOf[U] <:< typeOf[T] }
  }
}

val l = new A[Int] :: new A[String] :: new A[Boolean] :: HNil

object matcher extends Poly1 {
  implicit def default[T] = at[A[T]]{ a => l map a.matches }
}

l map matcher

每个项目都有一个匹配项,即结果是:

(true :: false :: false :: HNil) ::
(false :: true :: false :: HNil) ::
(false :: false :: true :: HNil) :: HNil

当我尝试在没有 TypeTags 的情况下重写示例时,matches 总是使用它的 no 大小写并返回 false:

import shapeless._

class A[T]{
    object matches extends Poly1 {
        implicit def yes = at[A[T]]{_ => true}
        implicit def no[U] = at[U]{_ => false}
    }
}

val l = new A[Int] :: new A[String] :: new A[Boolean] :: HNil

object matcher extends Poly1 {
    implicit def default[T] = at[A[T]]{ a => l map a.matches }
}

l map matcher

结果是:

(false :: false :: false :: HNil) ::
(false :: false :: false :: HNil) ::
(false :: false :: false :: HNil) :: HNil

是否可以在不使用 TypeTags 的情况下重写此示例并获得与第一种情况相同的结果?

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    看起来您真的希望能够部分应用更高等级的函数来干净地解决这个问题。这对于任何开箱即用的好语法都是不可能的,但我once wrote some code 帮助使它更容易一些(请注意,这都是 1.2.4):

    import shapeless._
    
    trait ApplyMapper[HF, A, X <: HList, Out <: HList] {
      def apply(a: A, x: X): Out
    }
    
    object ApplyMapper {
      implicit def hnil[HF, A] = new ApplyMapper[HF, A, HNil, HNil] {
        def apply(a: A, x: HNil) = HNil
      }
      implicit def hlist[HF, A, XH, XT <: HList, OutH, OutT <: HList](implicit
        pb: Poly.Pullback2Aux[HF, A, XH, OutH],
        am: ApplyMapper[HF, A, XT, OutT]
      ) = new ApplyMapper[HF, A, XH :: XT, OutH :: OutT] {
        def apply(a: A, x: XH :: XT) = pb(a, x.head) :: am(a, x.tail)
      }
    }
    

    有关上下文,请参阅上面链接的答案。

    这允许您编写以下内容:

    class A[T]
    
    object matches extends Poly2 {
      implicit def default[T, U](implicit sub: U <:< T = null) =
        at[A[T], A[U]]((_, _) => Option(sub).isDefined)
    }
    
    object mapMatcher extends Poly1 {
       implicit def default[T, X <: HList, Out <: HList](
         implicit am: ApplyMapper[matches.type, A[T], X, Out]
       ) = at[(A[T], X)] { case (a, x) => am(a, x) }
    }
    
    val l = new A[Int] :: new A[String] :: new A[Boolean] :: HNil
    

    可能有更好的解决方案,但目前我只有一分钟的时间来回应,它按原样工作:

    scala> l.zip(l mapConst l).map(mapMatcher).toList.foreach(println)
    true :: false :: false :: HNil
    false :: true :: false :: HNil
    false :: false :: true :: HNil
    

    根据需要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多