我一直在阅读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
获取它? - 因为我可以从显示的值中推导出来{ {1}}),然后将其传递给Status {statusCode = 200, statusMessage = "OK"}
,responseStatus
必须处理响应状态。所以,反过来说:实际上,状态代码是响应状态的一部分。
第二读对我来说也没有意义,因为它也首先处理状态代码。
答案 0 :(得分:13)
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.