使用 Maybe 遍历嵌套记录的更短方法

Posted

技术标签:

【中文标题】使用 Maybe 遍历嵌套记录的更短方法【英文标题】:Shorter way to traverse nested record with Maybe 【发布时间】:2017-09-05 00:09:28 【问题描述】:

是否有更短/更简洁的方式来编写以下 sn-p 代码:

fromMaybe "" $ fmap (^. fullName) (bi ^. bookerContact)

这里bi ^. bookerContact 可能会导致Maybe Contact 记录,这就是为什么需要对^. fullName 进行映射。在嵌套遍历之后,如果我们以 Nothing 结尾,我们使用 fromMaybe "" 将其默认为空字符串。

【问题讨论】:

【参考方案1】:

一种简单的整理方法是使用maybe 而不是fromMaybe/fmap 组合:

maybe "" (^. fullName) (bi ^. bookerContact)

您还可以引入_Just 棱镜将所有向下钻取表示为单个光学:

fromMaybe "" (bi ^? bookerContact . _Just . fullName)

请注意,我们已从 (^.) 切换到 (^?)。这反映了将_Just 添加到链中如何将过去的镜头(并且恰好到达一个目标)变成了遍历(可能没有到达任何目标)。


也可以利用 Text 作为一个幺半群并使用来自 Data.Foldablefold...

fold (bi ^? bookerContact . _Just . fullName)

... 或 foldOf,如果您更喜欢 lens 拼写:

foldOf (bookerContact . _Just . fullName) bi

正如the docs 指出的那样,foldOf 等同于(^.) (which is essentially view specialised to (->)),所以这也可以通过折叠Maybe Text

bi ^. bookerContact . _Just . fullName

【讨论】:

嗯...我不清楚bi ^. bookerContact._Just.fullName 的类型是如何变成Text 的。不应该是Maybe Text吗? ^. _Just over a Maybe Text 会导致 "" 但是 ^. _Just over a Maybe Int 会导致以下错误 - No instance for (Monoid Int) arising from a use of ‘_Just’ Is it possible to traverse over a @987654355 @ 以这样一种方式,即整个遍历导致 Maybe 不依赖于 Monoid 魔术? @SaurabhNanda “神奇”在于 Maybe Text 被折叠(为了比较,["foo", "bar"] ^. traverse 导致 "foobar")。如果您更喜欢获得Maybe Text 而不是折叠它,请使用(^?) 而不是(^.),如答案中的第二个和第三个变体。 (根据您可以接受的魔法数量,在这种情况下,您可能会看到 foldOf 在显式性方面比 (^.) 有所改进。) @PaulGardiner 我已经添加了文档的链接;谢谢你的建议。这在另一个方向上可能更容易理解:如果foo 是一个透镜,或者更一般地说是一个吸气剂,从sa(^.) 可以从@987654371 中提取a @ 值,因此 \s -> s ^. foo 是一个 s -> a 函数。 view 做了几乎相同的事情,只是它将结果推广到任意的MonadReader(即从s -> aMonadReader s m => m a)。另见this other answer of mine,它涉及到这个问题。 ^? 很干净。唯一不幸的是,lens 没有表达 仿射 遍历的方式,至少某些 profunctor 镜头公式会这样做。为了清楚起见,最好有一个特殊的运算符坚持其参数光学遍历最多一个元素。

以上是关于使用 Maybe 遍历嵌套记录的更短方法的主要内容,如果未能解决你的问题,请参考以下文章

如果索引列表遍历不匹配,则返回“Nothing”

Powershell:使用许多文件名执行命令的更短方法?

html 安全遍历运算符(与使用* ngIf相同但更短)

指定完成处理程序的更短方法

对象遍历,多层嵌套数组,for in方法对象遍历,map方法数组遍历

检查 jquery 的多个输入的值是不是为空的更短方法