What is the difference between `ix` and `at` in the Lens library of Haskell

风流意气都作罢 提交于 2019-11-29 02:57:30
bennofs

That at and ix are different is already noticable if you look at the available instances for the classes containing these functions:

  • instances of At: Map, IntMap, HashMap
  • instances of Ixed: [a], Map, ByteString, Text, and a lot more

All instances if At are also an instance of Ix, but not all instances of Ix are also an instance of At.

So what's the difference between them? At is for containers that allow inserting keys that are not present in the container. This is obviously possible for a Map, but not e.g. for a list. To still be able to index into a list and change items that are there, Ix doesn't allow creating new items, but just "does nothing" when you try to write to a key that is not there.

>>> 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

(There is also a shortcut for a .~ Just b, a ?~ b)

Technically, this difference comes from the fact that ix is a Traversal whereas at is a Lens. And because at is a Lens that "returns" a Maybe Something, you cannot compose it with a lens that takes just a plain "Something". ix is a Traversal with 0 or 1 values, so you can compose ix just like any other traversal (just like you can write traverse . traverse). (^?) just takes the first value (head) of that traversal.

You can always derive ix from at:

ixAt = at . traverse

The same definition is already in lens, except it's using (<.) for composition to keep the index from at. (at and ix are both indexed lenses / traversals).

Off-topic: Most operators from lens also have infix names, you can find a (incomplete) table at: https://github.com/ekmett/lens/wiki/Operators

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!