我一直在阅读this article,并在其中一部分中说明:
镜头倒退。我们不能让
(.)
表现得像函数一样吗?你是对的,我们可以。我们不是出于各种原因,但是 直觉是对的。镜片应该像功能一样组合。一 对于那个重要的事情是id可以预先或后 用任何镜头构成而不影响它。
镜头构成向后的意思是什么?
此外,这意味着什么:我们不能让(.)
表现得像函数一样吗?
(.)
是一个函数,通过将它与Lens一起使用,它会使(.)
表现得像其他吗?
答案 0 :(得分:6)
Lens
类型:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
出于说明的目的,我们可以坚持使用较不普遍的简单镜头类型Lens'
。然后右侧变为:
forall f. Functor f => (a -> f a) -> s -> f s
直观地,(a -> f a)
是对s
类型结构的一部分的操作,它被提升为整个结构(s -> f s)
的操作。 (仿函数类型构造函数f
是诡计的一部分,它允许镜头概括getter,setter和许多其他东西。我们现在不需要担心它。)换句话说:
(请注意,在我刚刚做的描述中,"部分"以及"整体"出现在不同的订单中。)
现在,镜头是一个功能,可以组成功能。众所周知,(.)
有类型:
(.) :: (y -> z) -> (x -> y) -> (x -> z)
让我们让所涉及的类型变成简单的镜头(为了清楚起见,我将删除约束和forall
)。 x
变为a -> f a
,y
变为s -> f s
,z
变为t -> f t
。那么(.)
的专用类型就是:
((s -> f s) -> t -> f t) -> ((a -> f a) -> s -> f s) -> ((a -> f a) -> t -> f t)
我们得到的镜头的类型为(a -> f a) -> (t -> f t)
。因此,合成镜头firstLens . secondLens
对由secondLens
聚焦的部分进行操作,并使其成为整个结构firstLens
的目标。这恰好与组成OO样式字段引用的顺序相匹配,这与组成vanilla Haskell记录访问器的顺序相反。
答案 1 :(得分:4)
您可以将镜头的Getter
部分视为一个功能,您可以使用view
进行提取。例如,编写fst
函数的镜头方式是:
view _1 :: (a,b) -> a
现在观察:
view _1 . view _2 :: (c, (a,b)) -> a -- First take the second pair element, then the first
view (_1 . _2) :: ((b,a) ,c) -> a -- This is "backwards" (exactly the opposite order of the above)
对于镜头,(.)
的功能与功能不同。对于函数,f . g
表示“首先应用g,然后是f”,但对于镜头,则表示first use the lens f, then use the lens g
。实际上,(.)
函数对于这两种类型都是相同的,但镜头类型使它看起来像是向后的。