14

我已经看到一个名为“at”的对象(可能是一个函数)散布在无形的源代码和使用无形的代码中。特别是,它用于回答这个其他问题。这是代码片段:

object iterateOverHList extends Poly1 {
  implicit def iterable[T, L[T] <: Iterable[T]] = at[L[T]](_.iterator)
}

我有一些线索表明它与 ~> 类型的 apply 方法有关。“at”具体做什么,在哪里定义?

4

3 回答 3

11

的定义PolyN#at

at是一种通用的工作方式Poly

~>withapply是 的一个特例。这里用于定义隐式方法:Poly1applyat

implicit def caseUniv[T] = at[F[T]](apply(_))

方法at定义PolyN(例如)中,如下Poly1所示:

trait PolyN extends Poly { outer =>
  type Case[T1, T2, ..., TN] = poly.Case[this.type, T1 :: T2 :: ... :: TN :: HNil]
  object Case {
    type Aux[T1, T2, ..., TN, Result0] = poly.Case[outer.type, T1 :: T2 :: ... :: TN :: HNil] { type Result = Result0 }
  }

  class CaseBuilder[T1, T2, ..., TN] {
    def apply[Res](fn: (T1, T2, ..., TN) => Res) = new Case[T1, T2, ..., TN] {
      type Result = Res
      val value = (l: T1 :: T2 :: ... :: TN :: HNil) => l match {
        case a1 :: a2 :: ... :: aN :: HNil => fn(a1, a2, ..., aN)
      }
    }
  }

  def at[T1, T2, ..., TN] = new CaseBuilder[T1, T2, ..., TN]
}

在以下情况下Poly1

trait Poly1 extends Poly { outer =>
  type Case[T1] = poly.Case[this.type, T1 :: HNil]
  object Case {
    type Aux[T1, Result0] = poly.Case[outer.type, T1 :: HNil] { type Result = Result0 }
  }

  class CaseBuilder[T1] {
    def apply[Res](fn: (T1) => Res) = new Case[T1] {
      type Result = Res
      val value = (l: T1) => l match {
        case a1 :: HNil => fn(a1)
      }
    }
  }

  def at[T1] = new CaseBuilder[T1]
}

所以at[Int]创建一个 and 的实例,CaseBuilder[Int]或者at[Int].apply[String](_.toString)只是(用于方法调用的at[Int](_.toString)语法糖)创建一个.applypoly.Case[this.type, Int :: HNil]{ type Result = String }

因此,implicit def iterable[T, L[T] <: Iterable[T]] = at[L[T]](_.iterator)您可以创建一个隐式方法来创建poly.Case[this.type, L[T] :: HNil]{ type Result = Iterator[T] }.

这种隐式方法用于map(和其他一些多态函数)。

实施HList#map

map is defined like this:

def map(f : Poly)(implicit mapper : Mapper[f.type, L]) : mapper.Out = mapper(l)

(L is the type of HList)

To create a Mapper compiler looks for Case1[Fn, T].

For map(f) on A :: B :: ... :: HNil compiler have to find implicits for Case1[f.type, A], Case1[f.type, B] and so on.

In case of List[Int] :: HNil the only implicit Case1 needed is Case1[f.type, List[Int]].

Note that Case1 is defined like this:

type Case1[Fn, T] = Case[Fn, T :: HNil]

So we have to find an implicit value for Case[f.type, List[Int] :: HNil].

In case f is an object one of the places to search for implicits is f fields and methods. So compiler will find Case defined in f.

于 2014-01-04T05:56:13.807 回答
7

我不是专业人士,所以@miles-sabin 和@travis-brown 可以给出完整和更明确的答案,但是我也可以尝试(它不完整并且没有显示所有正式问题):

  1. iterateOverHList它是一个多态函数 extends Poly1,如果你看一下这个 ( Poly1) 特征的实现,你会发现它只将你的 exmpl 中键入的一个对象作为参数作为L[T];

  2. 函数at的确切含义(看下面的实现):“在类型L[T]应用函数的情况下at;所以在你的对象的 exmpl 方法iterator中。所以你可以编写不同的隐式函数,可以应用于不同的类型,当你遍历时它很有用a HList(例如带有地图)具有不同且困难的类型。

上面的特征的实现Poly和我的话的证明你可以在这里找到例如:http: //xuwei-k.github.io/shapeless-sxr/shapeless-2.10-2.0.0-M1/polyntraits.scala.html 这里我们看到这个Poly1特征是:

trait Poly1 extends Poly { outer =>
    type Case[A] = poly.Case[this.type, A :: HNil]
    object Case {
        type Aux[A, Result0] = poly.Case[outer.type, A :: HNil] { type Result = Result0 }
    }

    class CaseBuilder[A] {
        def apply[Res](fn: (A) => Res) = new Case[A] {
            type Result = Res
            val value = (l : A :: HNil) => l match { case a :: HNil => fn(a) }
        }
    }

    def at[A] = new CaseBuilder[A]
}
于 2014-01-03T22:13:41.320 回答
2

这很难找到,因为shapelessPolyN中的类是通过 Boilerplate.scala 自动生成的。

除了Poly0, 你可以在这里看到

简而言之......这只是一种方法Poly1

于 2014-01-03T23:29:11.397 回答