如何构成"Maybe"个镜头?
How to compose "Maybe" lenses?
如果我有用于嵌套记录的镜头,其中每个镜头 returns 一个 Maybe
,我怎样才能让它们合成,以便 "traversal" returns一个Nothing
最后的结果是一个Nothing
?
data Client = Client
{
clientProperties :: Maybe Properties
, ...
}
data Properties = Properties
{
propSmtpConfig :: Maybe SmtpConfig
, ...
}
c :: Client
c = undefined
smtp = c ^. (properties . smtpConfig) -- How to make these lenses compose?
编辑 我尝试了很多选项,但这是我能想到的最好的。寻找更清洁的东西:
(client ^. properties) >>= (view smtpConfig)
您可以使用_Just
prism。这是一个人为的例子:
> (Just (Just 1, ()), ()) & _1 . _Just . _1 . _Just +~ 1
(Just (Just 2,()),())
你的情况,我想你想要
properties . _Just . smtpConfig . _Just
traverse
是有效的Traversal
,记住。
getSmtpConfig :: Traversal' Client SmtpConfig
getSmtpConfig = properties . traverse . smtpConfig . traverse
Traversal
是你在这里能做的最好的 - 你不能得到 Lens
- 因为可能没有 SmtpConfig
。 (Lens
表示 "there's always exactly one of these things",而 Traversal
表示 "there may be zero or many"。)
这段代码实际上产生了与您使用 相同的 Traversal
,但如果您还没有 grokked 棱镜,它可能更容易理解。
请注意,由于 Traversal
可能找不到任何结果,因此您不能使用 ^.
to access a single result as you did in your question. You need to use the "safe head" operator ^?
(aka flip preview
)。
smtp :: Maybe SmtpConfig
smtp = c^?properties.traverse.smtpConfig.traverse
client ^? properties . _Just . smtpConfig . _Just
编辑:像透镜这样的光学器件可以将小动作变成大动作。光学构图是函数构图。 _Just
将 a
上的操作转换为 Maybe a
上的操作。镜头可以将阅读的小动作变成阅读的大动作,将书写的小动作变成书写的大动作,但是_Just
无法处理阅读动作,因为Nothing
中没有a
。因此_Just
是一种比透镜弱的光学,一种穿越。复合光学器件始终可以准确地处理所有部件都可以处理的那些动作。所以properties . _Just . smtpConfig . _Just
是一次遍历。 (^?)
使用遍历可以处理的读取操作的变体:“也许读取一个值”。因此,上面的行将平凡成功的阅读操作 Just :: SmtpConfig -> Maybe SmtpConfig
变成了一个大的阅读操作 Client -> Maybe SmtpConfig
.
如果我有用于嵌套记录的镜头,其中每个镜头 returns 一个 Maybe
,我怎样才能让它们合成,以便 "traversal" returns一个Nothing
最后的结果是一个Nothing
?
data Client = Client
{
clientProperties :: Maybe Properties
, ...
}
data Properties = Properties
{
propSmtpConfig :: Maybe SmtpConfig
, ...
}
c :: Client
c = undefined
smtp = c ^. (properties . smtpConfig) -- How to make these lenses compose?
编辑 我尝试了很多选项,但这是我能想到的最好的。寻找更清洁的东西:
(client ^. properties) >>= (view smtpConfig)
您可以使用_Just
prism。这是一个人为的例子:
> (Just (Just 1, ()), ()) & _1 . _Just . _1 . _Just +~ 1
(Just (Just 2,()),())
你的情况,我想你想要
properties . _Just . smtpConfig . _Just
traverse
是有效的Traversal
,记住。
getSmtpConfig :: Traversal' Client SmtpConfig
getSmtpConfig = properties . traverse . smtpConfig . traverse
Traversal
是你在这里能做的最好的 - 你不能得到 Lens
- 因为可能没有 SmtpConfig
。 (Lens
表示 "there's always exactly one of these things",而 Traversal
表示 "there may be zero or many"。)
这段代码实际上产生了与您使用 Traversal
,但如果您还没有 grokked 棱镜,它可能更容易理解。
请注意,由于 Traversal
可能找不到任何结果,因此您不能使用 ^.
to access a single result as you did in your question. You need to use the "safe head" operator ^?
(aka flip preview
)。
smtp :: Maybe SmtpConfig
smtp = c^?properties.traverse.smtpConfig.traverse
client ^? properties . _Just . smtpConfig . _Just
编辑:像透镜这样的光学器件可以将小动作变成大动作。光学构图是函数构图。 _Just
将 a
上的操作转换为 Maybe a
上的操作。镜头可以将阅读的小动作变成阅读的大动作,将书写的小动作变成书写的大动作,但是_Just
无法处理阅读动作,因为Nothing
中没有a
。因此_Just
是一种比透镜弱的光学,一种穿越。复合光学器件始终可以准确地处理所有部件都可以处理的那些动作。所以properties . _Just . smtpConfig . _Just
是一次遍历。 (^?)
使用遍历可以处理的读取操作的变体:“也许读取一个值”。因此,上面的行将平凡成功的阅读操作 Just :: SmtpConfig -> Maybe SmtpConfig
变成了一个大的阅读操作 Client -> Maybe SmtpConfig
.