29

我只知道一个有效,另一个无效。

上下文: 我有一个数据结构F,其中包含Data.Map.Map k S另一个数据结构S。我的目标是建立一个Lens给定的F并且k将描述一个领域的S.

困难在于k地图中可能不存在密钥。很好,该函数可以将其返回值包装在 Maybe 中。但是我无法通过 Maybe using 传播镜头at。在阅读了很多 Stack Overflow 的答案后,我遇到了这个

事实证明,如果我也at替换为.ix(^.)(^?)

问题: 看起来atix做同样的事情,至少在Map. 两者都取一个键并为该键的值提供一个“镜头”。但是,ix似乎与函数组合运算符配合得很好(.)。两者有什么区别?


离题咆哮:

我和其他人一样喜欢中缀运算符,但 Control.Lens 包似乎有点过火了。对于一个有一些英文名字和某个地方的键的新用户来说,学习曲线会降低。由于 Lens 库中使用了大量的包装类,如果您还不知道发生了什么,则特别难以挖掘类型签名。看在老天的份上,我的代码开始看起来像 Perl。

4

1 回答 1

25

如果您查看包含这些函数的类的可用实例,那么它们的不同已经很明显at了:ix

  • 实例At:Map、IntMap、HashMap
  • 实例Ixed:[a]、Map、ByteString、Text 等等

所有实例 ifAt也是 的实例Ix,但并非所有实例Ix也是 的实例At

那么它们之间有什么区别呢?At用于允许插入容器中不存在的键的容器。这对于 Map 显然是可能的,但对于列表来说却不是这样。为了仍然能够索引到列表并更改那里的Ix项目,不允许创建新项目,而是在您尝试写入不存在的键时“什么都不做”。

>>> Data.Map.fromList [('a', 1)] & at 'b' .~ Just 4 
fromList [('a',1),('b',4)] -- Inserts value 
>>> Data.Map.fromList [('a', 1)] & ix 'b' .~ 4  
fromList [('a',1)]          -- Does nothing because key is not present

(还有 , 的快捷a .~ Just b方式a ?~ b

从技术上讲,这种差异来自TraversalLensix的事实。并且因为是“返回” Maybe Something 的镜头,所以您不能用只拍摄普通“Something”的镜头来构图。是一个具有 0 或 1 值的遍历,因此您可以像任何其他遍历一样编写 ix(就像您可以编写 一样)。只取该遍历的第一个值(头)。atatixtraverse . traverse(^?)

你总是可以ixat

ixAt = at . traverse

相同的定义已经在 lens 中,除了它使用(<.)for composition 来保持索引从 at。(at并且ix都是索引镜头/遍历)。

题外话:镜头中的大多数运算符也有中缀名称,您可以在以下位置找到一个(不完整的)表:https ://github.com/ekmett/lens/wiki/Operators

于 2013-08-24T02:20:36.590 回答