无形(scala)中的“at”是什么?

时间:2014-01-03 21:06:20

标签: scala shapeless

我已经看到一个名为“at”的对象(可能是一个函数)散布在整个无形源和使用无形的代码中。特别是,它用于this other question的答案。以下是代码段:

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

我有一些线索,它与〜&gt;的apply方法有关。类型。 “at”具体做什么,它在哪里定义?

3 个答案:

答案 0 :(得分:10)

PolyN#at

的定义

at是使用Poly的一般方法。

~>apply的{​​{1}}是Poly1 applyat此处用于使用implicit def caseUniv[T] = at[F[T]](apply(_)) 定义隐式方法:

at

方法PolyN Poly1 special case defined,例如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]

因此CaseBuilder[Int]创建at[Int].apply[String](_.toString)at[Int](_.toString)apply的实例(poly.Case[this.type, Int :: HNil]{ type Result = String }方法调用的synax糖)创建{{1}的实例}}

因此,使用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是这样的defined

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

LHList)的类型

Mapper创建Case1[Fn, T]编译器looks

map(f) A :: B :: ... :: HNil编译器必须找到Case1[f.type, A]Case1[f.type, B]的含义等等。

如果List[Int] :: HNil,则唯一隐含的Case1Case1[f.type, List[Int]]

请注意,Case1defined,如下所示:

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

所以我们必须找到Case[f.type, List[Int] :: HNil]的隐含值。

如果fobject,其中一个搜索implicits的地方是f字段和方法。因此编译器会在Case中找到f

答案 1 :(得分:7)

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

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

  2. 函数at的确意味着(查看下面的实现):“如果类型L[T]at中应用函数;那么在你的exmpl方法中iterator你的对象 因此,您可以编写可应用于不同类型的不同隐式函数,当您浏览具有不同类型和难度类型的HList(例如带有地图)时,它非常有用。

  3. 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]
    }
    

答案 2 :(得分:1)

这是一个很难找到的,因为无形的PolyN类是通过Boilerplate.scala自动生成的。

Poly0以外的所有内容,您可以看到here

简而言之......这只是Poly1

上的一种方法