使用镜头更新嵌套数据结构

问题描述

我目前正在尝试使用镜头使代码的部分更简洁。特别是,我有一个HTTP Request,我想在其中将标头的值替换为名称Private-Header

我设法编写了更新RequestHeaders函数

updateHeaders :: RequestHeaders -> RequestHeaders
updateHeaders headers = headers & traverse . filtered (\header -> fst header == "Private-Header") %~ set _2 "xxxxxx"

但是,我正在努力提出一个从请求中提取标头并更新它们的函数。没有镜头,它看起来可能像这样:

updateRequest :: Request -> Request
updateRequest req = req {requestHeaders = updateHeaders (requestHeaders req)}

有没有办法使用镜头实现此功能

解决方法

当然。首先,您需要一个光学元件来表示"Private-Header"对象中RequestHeaders标头的值。合理的候选对象是遍历,它允许在另一种类型中出现零次或多次出现。 (通常,您只有零个或一个私有标头,但是RequestHeader类型并没有阻止两个或多个同名标头的基本知识,因此遍历似乎是最安全的选择。)

此光学元件的合适类型是:

privateHeader :: Traversal' RequestHeaders ByteString

您已经完成了updateHeaders中定义此光学元件的大部分工作,您只需要重新排列零件。表达式:

traverse . filtered (\header -> fst header == "Private-Header")

是一种光学器件,可从Header中提取匹配的RequestHeader值。只要您不使用它来修改键并中断过滤,它都是有效的遍历,因此我们可以直接将其与镜头_2组合以创建一个新的遍历,该遍历从{{1 }}:

type Header = (ByteString,ByteString)

顺便说一下,这种新的遍历也使我们能够简化privateHeader = traverse . filtered (\header -> fst header == "Private-Header") . _2 的实现。

updateHeaders

第二,我们需要一个光学器件来表示updateHeaders :: RequestHeaders -> RequestHeaders updateHeaders = set privateHeader "xxxxxx" 的{​​{1}}字段的值。您可以使用RequestHeaders函数构建一个:

Request

现在,您可以组成lensheaders :: Lens' Request RequestHeaders headers = lens getter setter where getter = requestHeaders setter req hdrs = req { requestHeaders = hdrs } 来创建新的遍历:

headers

privateHeaders可以实现为:

privateHeaderInRequest :: Traversal' Request ByteString
privateHeaderInRequest = headers . privateHeader

完整代码:

updateRequest

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...