我一直在读A wreq tutorial:
镜头提供了一种聚焦于Haskell值一部分的方法。对于
例如,Response
类型具有responseStatus
镜头,
着重于服务器返回的状态信息。
ghci> r ^. responseStatus
Status {statusCode = 200, statusMessage = "OK"}
^.
运算符将值作为第一个参数,将镜头作为其参数第二,并返回镜头聚焦的部分值。
我们使用功能组合来构成镜头,这使我们能够
轻松关注深层嵌套结构的一部分。
ghci> r ^. responseStatus . statusCode
200
我想不出一种方法,用此顺序的参数完成函数组合可以按该顺序处理嵌套结构。
外观:
r ^. responseStatus . statusCode
可以是r ^. (responseStatus . statusCode)
或(r ^. responseStatus) . statusCode
。在第一个语句中,我们构造了一个函数,首先处理
statusCode
(从记录Status
?中获取它-我可以从显示的值Status {statusCode = 200, statusMessage = "OK"}
推导出来),然后将其传递给responseStatus
,该必须处理响应状态。因此,反之亦然:实际上,状态代码是响应状态的一部分。二读对我来说也没有意义,因为它也首先处理状态码。
最佳答案
正确阅读r ^. responseStatus . statusCode
是r ^. (responseStatus . statusCode)
。这是很自然的,因为函数组合在应用于两个参数时会返回一个函数,因此(r ^. responseStatus) . statusCode
必须返回一个函数,而不是可以打印出的任何值。
这仍然悬而未决,为什么镜片会以“错误”的顺序组成。由于镜头的实现有些不可思议,因此让我们来看一个简单的示例。first
是一个映射成对的第一个元素的函数:
first :: (a -> b) -> (a, c) -> (b, c)
first f (a, b) = (f a, b)
map . first
是做什么的? first
接受作用在第一个元素上的函数,并返回作用在对上的函数,如果我们用这种方式将类型括起来,则更明显:first :: (a -> b) -> ((a, c) -> (b, c))
另外,还记得
map
的类型:map :: (a -> b) -> ([a] -> [b])
map
接受作用于元素的函数,并返回作用于列表的函数。现在,f . g
可以通过首先应用g
然后将结果提供给f
来工作。因此,map . first
接受作用于某种元素类型的函数,将其转换为作用于对的函数,然后将其转化为作用于对的列表的函数。(map . first) :: (a -> b) -> [(a, c)] -> [(b, c)]
first
和map
都将作用在结构的一部分上的函数转换为作用在整个结构上的函数。在map . first
中,first
的整个结构是map
的重点。(map . first) (+10) [(0, 2), (3, 4)] == [(10, 2), (13, 4)]
现在看一下镜头的类型:
type Lens = forall f. Functor f => (a -> f b) -> (s -> f t)
现在尝试忽略
Functor
位。如果我们斜视一下,这类似于map
和first
的类型。碰巧的是,镜头还将作用在结构部分上的功能转换为作用在整个结构上的功能。在上面的签名中,s
表示整个结构,而a
表示其一部分。由于我们的输入函数可以将a
的类型更改为b
(如a -> f b
所示),因此我们还需要t
参数,该参数的大致含义是“在将s
更改为a
之后,b
的类型”。statusCode
是一个将作用于Int
的函数转换为作用于Status
的函数的镜头:statusCode :: Functor f => (Int -> f Int) -> (Status -> f Status)
responseStatus
将作用于Status
的函数转换为作用于Response
的函数:responseStatus :: Functor f => (Status -> f Status) -> (Response -> f Response)
responseStatus . statusCode
的类型遵循与map . first
相同的模式:responseStatus . statusCode :: Functor f => (Int -> f Int) -> (Response -> f Response)
^.
到底如何工作还有待观察。它与镜头的核心机制和魔力息息相关。我不会在这里重申它,因为有很多关于它的著作。作为介绍,我建议您查看this one和this one,您也可以观看this excellent video.