繁体   English   中英

Haskell如何使用奇怪的参数顺序实现“使用函数组合构成镜头”?

[英]How Haskell's “composing lenses using function composition” with that weird order of arguments could be implemented?

我一直在阅读一个wreq教程

镜头提供了一种聚焦于Haskell值的一部分的方法。 例如, Response类型有一个responseStatus镜头,它关注服务器返回的状态信息。

 ghci> r ^. responseStatus Status {statusCode = 200, statusMessage = "OK"} 

^. operator将一个值作为其第一个参数,将镜头作为其第二个参数,并返回镜头聚焦的值部分。

我们使用功能组合构成镜头,这使我们可以轻松地专注于深层嵌套结构的一部分。

 ghci> r ^. responseStatus . statusCode 200 

我无法想出如何使用这个参数顺序完成的函数组合可以按顺序处理嵌套结构。

看: r ^. responseStatus . statusCode r ^. responseStatus . statusCode r ^. responseStatus . statusCode可以是r ^. (responseStatus . statusCode) r ^. (responseStatus . statusCode)(r ^. responseStatus) . statusCode 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 r ^. responseStatus . statusCoder ^. (responseStatus . statusCode) 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 map . first呢? first接受一个作用于第一个元素的函数,并返回一个作用于一对的函数,如果我们用这种方式括起这个类型就更明显了:

first :: (a -> b) -> ((a, c) -> (b, c))

另外,回想一下map的类型:

map :: (a -> b) -> ([a] -> [b])

map接受一个作用于元素的函数,并返回一个作用于列表的函数。 现在, f . g f . g首先应用g然后将结果输入f 所以map . first map . first获取一个作用于某个元素类型的函数,将其转换为作用于对的函数,然后将其转换为作用于对列表的函数。

(map . first) :: (a -> b) -> [(a, c)] -> [(b, c)]

first ,将作用于结构一部分的转向函数map到作用于整个结构的函数。 map . first 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尝试忽略Functor位。 如果我们略微眯眼,这类似于mapfirst的类型。 它的发生使得镜头还将作用于结构部件的功能转换为作用于整个结构的功能。 在上面s签名中, s表示整个结构, a表示它的一部分。 由于我们的输入函数可以改变的类型ab (由作为指示的a -> fb ),我们还需要t参数“的类型,它粗略意味着s我们改变后ab里面”。

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的类型responseStatus . statusCode responseStatus . statusCode遵循我们在map . first看到的相同模式map . first map . first

responseStatus . statusCode :: Functor f => (Int -> f Int) -> (Response -> f Response)

还有待观察^. 作品。 它与镜头的核心机制和魔力密切相关; 我不会在这里重申,因为有很多关于它的着作。 对于介绍我建议看这个这个 ,你也可以看这个优秀的视频。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM