我一直在阅读这篇文章,并在其中一个部分中指出:
镜头向后构图。我们不能让
(.)
行为像函数吗?你是对的,我们可以。我们不是出于各种原因,但直觉是对的。镜头应该像功能一样组合。重要的一件事是 id 可以在不影响任何镜头的情况下预先或后期组合任何镜头。
镜头向后组合是什么意思?
另外,这是什么意思:我们不能让(.)
行为像函数吗?
(.)
是一个函数,通过将它与 Lens 一起使用,它是否会(.)
表现得像其他东西?
我一直在阅读这篇文章,并在其中一个部分中指出:
镜头向后构图。我们不能让
(.)
行为像函数吗?你是对的,我们可以。我们不是出于各种原因,但直觉是对的。镜头应该像功能一样组合。重要的一件事是 id 可以在不影响任何镜头的情况下预先或后期组合任何镜头。
镜头向后组合是什么意思?
另外,这是什么意思:我们不能让(.)
行为像函数吗?
(.)
是一个函数,通过将它与 Lens 一起使用,它是否会(.)
表现得像其他东西?
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)
结果我们得到的镜头有 type (a -> f a) -> (t -> f t)
。因此,合成镜头firstLens . secondLens
对所聚焦的部分进行操作,secondLens
并使其成为对所针对的整个结构的操作firstLens
。这恰好与组合 OO 样式字段引用的顺序相匹配,这与普通 Haskell 记录访问器的组合顺序相反。
您可以将Getter
镜头的一部分视为一个函数,您可以使用view
. 例如写fst
函数的lens方式是:
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
. 实际上,(.)
这两种类型的功能是相同的,但是镜头的类型使它看起来像是倒退了。