镜头:向后组合和镜头上下文中的(。)

时间:2014-04-15 19:15:47

标签: haskell lens

我一直在阅读this article,并在其中一部分中说明:

  

镜头倒退。我们不能让(.)表现得像函数一样吗?

     

你是对的,我们可以。我们不是出于各种原因,但是   直觉是对的。镜片应该像功能一样组合。一   对于那个重要的事情是id可以预先或后   用任何镜头构成而不影响它。

镜头构成向后的意思是什么?

此外,这意味着什么:我们不能让(.)表现得像函数一样吗?

(.)是一个函数,通过将它与Lens一起使用,它会使(.)表现得像其他吗?

2 个答案:

答案 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 ay变为s -> f sz变为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。实际上,(.)函数对于这两种类型都是相同的,但镜头类型使它看起来像是向后的。