我已经看到一个名为"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] :: HNil
只Case1
需要隐含的话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]
.
如果f
是object
搜索implicits的地方之一是f
字段和方法.所以编译器会找到Case
定义的f
.
我不是专业人士,所以@ miles-sabin和@travis-brown可以提供完整而明确的答案,但是我也可以尝试(它不完整,并没有显示所有正式问题):
iterateOverHList
它是一个多态函数,扩展Poly1
,如果你看这个(Poly1
)特性的实现,你会发现它只需要在你的exmpl中键入一个对象作为参数L[T]
;
函数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)
归档时间: |
|
查看次数: |
1278 次 |
最近记录: |