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

jcr*_*udy 13 scala shapeless

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

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

我有一些线索,它与〜>类型的apply方法有关."at"具体做什么,它在哪里定义?

sen*_*nia 10

的定义 PolyN#at

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

~>apply一个特殊情况Poly1.apply这里用于定义隐式方法at:

implicit def caseUniv[T] = at[F[T]](apply(_))
Run Code Online (Sandbox Code Playgroud)

方法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]
}
Run Code Online (Sandbox Code Playgroud)

在以下情况下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]
}
Run Code Online (Sandbox Code Playgroud)

因此at[Int]创建一个CaseBuilder[Int]和/ at[Int].apply[String](_.toString)或只是at[Int](_.toString)(apply方法调用的synax糖)的实例创建一个实例poly.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定义如下:

def map(f : Poly)(implicit mapper : Mapper[f.type, L]) : mapper.Out = mapper(l)
Run Code Online (Sandbox Code Playgroud)

(L是类型HList)

要创建一个Mapper编译器看起来Case1[Fn, T].

对于map(f)on A :: B :: ... :: HNil编译器必须找到implicits Case1[f.type, A],Case1[f.type, B]等等.

如果List[Int] :: HNilCase1需要隐含的话Case1[f.type, List[Int]].

需要注意的是Case1定义是这样的:

type Case1[Fn, T] = Case[Fn, T :: HNil]
Run Code Online (Sandbox Code Playgroud)

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

如果fobject搜索implicits的地方之一是f字段和方法.所以编译器会找到Case定义的f.


Dau*_*nnC 7

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

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

  2. 函数at正好意味着(看下面的实现):"如果类型中包含L[T]apply函数at;那么在你iterator的对象的exmpl方法中.所以你可以编写不同的隐式函数,可以应用于不同的类型,当你走过时它很有用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]
}
Run Code Online (Sandbox Code Playgroud)