根据Control.Foldl documentation:
任何镜头,遍历或棱镜都会作为处理程序进行打字检查
type Handler a b
= forall x. (b -> Constant (Endo x) b) -> a -> Constant (Endo x) a
有人可能声称,因为镜头允许任何Functor
不是Constant
镜片的唯一子集应进行类型检查。为什么这个陈述不正确?
答案 0 :(得分:5)
你的指示混乱了。这里描述的光学器件都是
形式 type Foo s t a b = forall f. SomeConstraints f => (a -> f b)-> (s -> f t)
对于棱镜而言,它应该与任意Choice
运算符一起工作,但->
是这种结构的典型例子,所以我们可以专门研究棱镜只适用于这些影响者。这个过程合法的原因与我们对f
的处理方式相同,因此暂停一分钟的怀疑并阅读
现在,如果我们将s
和t
实例化为a
,将a
和b
实例化为b
,那么我们就会
forall f. SomeConstraints f => (b -> f b) -> (a -> f a)
现在这意味着如果我们有一些光学器件,如透镜,棱镜或遍历,我们可以实例化其类型参数,使其几乎以Handler
的形式存在。唯一的区别是我们保证适用于任何f
,只要它满足我们选择的约束。如果我们知道Constant (Endo x)
满足这些约束条件,那么我们可以默默地将该光学元件专门用于仅使用f
。这只是简单的多态实例化!由于Constant a
是Functor
和Applicative
,因此它适用于任何镜头或遍历。这种隐含的子类型和实例化是使镜头包工作的核心,通过将所有这些事物保持透明,Haskell让我们混合和匹配抽象,它将自动落在最大的下限上#34 ;无论我们使用什么样的光学器件。
整个事情归结为这样的事实:在Haskell中,如果我们有e :: forall t. T
,那么对于任何适当的k tau
我们也有e :: [tau/t]T
。一旦我们抛出类型约束,就会有一些皱纹,但总的来说,所有这些都只是默认情况下Haskell中类型应用程序是静默的。