我已经看到一个名为“at”的对象(可能是一个函数)散布在整个无形源和使用无形的代码中。特别是,它用于this other question的答案。以下是代码段:
object iterateOverHList extends Poly1 {
implicit def iterable[T, L[T] <: Iterable[T]] = at[L[T]](_.iterator)
}
我有一些线索,它与〜&gt;的apply方法有关。类型。 “at”具体做什么,它在哪里定义?
答案 0 :(得分:10)
PolyN#at
at
是使用Poly
的一般方法。
~>
与apply
的{{1}}是Poly1
apply
。 at
此处用于使用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)
(L
是HList
)的类型
为Mapper
创建Case1[Fn, T]
编译器looks。
map(f)
A :: B :: ... :: HNil
编译器必须找到Case1[f.type, A]
,Case1[f.type, B]
的含义等等。
如果List[Int] :: HNil
,则唯一隐含的Case1
是Case1[f.type, List[Int]]
。
请注意,Case1
是defined,如下所示:
type Case1[Fn, T] = Case[Fn, T :: HNil]
所以我们必须找到Case[f.type, List[Int] :: HNil]
的隐含值。
如果f
是object
,其中一个搜索implicits的地方是f
字段和方法。因此编译器会在Case
中找到f
。
答案 1 :(得分:7)
我不是专业人士,所以@ miles-sabin和@ travis-brown可以给出完整而明确的答案,但是我也可以尝试(它不完整,并没有显示所有正式问题):
iterateOverHList
这是一个多态函数,扩展Poly1
,如果你看这个(Poly1
)特征的实现,你会看到它仅作为参数在你的exmpl中键入一个对象L[T]
;
函数at
的确意味着(查看下面的实现):“如果类型L[T]
在at
中应用函数;那么在你的exmpl方法中iterator
你的对象
因此,您可以编写可应用于不同类型的不同隐式函数,当您浏览具有不同类型和难度类型的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]
}
答案 2 :(得分:1)