Listing at a specific location using lenses

I am trying to manipulate a nested data structure containing lists of items. After tricking me with various approaches, I finally settled on lenses as the best way to do this. They work great for finding and modifying certain structural elements, but so far I don’t understand how to add new elements.

From what I read, I cannot technically use Traversal, since it violates the laws of Traversal to insert a new item into the list, and suggesting that I could even figure out how to do this using Traversal in the first place (I still it's pretty weak with Haskell, and type signatures for most things in the lens package make my head spin).

In particular, what I'm trying to do is find some element in the list of elements that matches a particular selector, and then insert a new element either before or after the matched element (another function argument before or after the match). Does Control.Lens already have something that can accomplish what I'm trying to do, and my understanding of type signatures is too weak to see this? Is there a better way to accomplish what I'm trying to do?

It would be rather trivial if I were just trying to add a new element either to the beginning or to the end of the list, but its difficult part is a place somewhere somewhere in between. In some of the pre-object codes that I wrote, I used the fold to accomplish what I wanted, but it began to push into more deeply nested parts of the structure (EG - fold inside the fold inside the fold), so I turned to Control. Lens to try to unravel some of these riots.

+6
source share
3 answers

Using lens pacakge

If we start with the fact that the id function can be used as a lens:

 import Control.Lens > [1,2,3,4] ^. id [1,2,3,4] 

Then we can move on to how the list can be changed:

 > [1,2,3,4] & id %~ (99:) [99,1,2,3,4] 

The above allows you to insert at the top of the list. To focus on the last parts of the list, we can use _tail from the Control.Lens.Cons module .

 > [1,2,3,4] ^. _tail [2,3,4] > [1,2,3,4] & _tail %~ (99:) [1,99,2,3,4] 

Now, to generalize this to the nth position

 > :{ let _drop 0 = id _drop n = _tail . _drop (n - 1) :} > [1,2,3,4] ^. _drop 1 [2,3,4] > [1,2,3,4] & _drop 0 %~ (99:) [99,1,2,3,4] > [1,2,3,4] & _drop 1 %~ (99:) [1,99,2,3,4] 

The final step is to generalize this to all types using the Cons instance , we can use Cons or <| .

 > [1,2,3,4] & _drop 1 %~ (99<|) [1,99,2,3,4] > import Data.Text > :set -XOverloadedStrings > ("h there"::Text) & _drop 1 %~ ('i'<|) "hi there" 
+4
source

I think a simple approach could solve the problem in:

  • The function [a] -> SomeAddtionalData -> [a] , which is mainly responsible for converting the list to another list using some specific data. Here you add / remove items from the list and get a new list
  • Use lense to extract a list from some nested data structure, pass this list to the above functions, set the returned list to a nested data structure using lense.

Your last paragraph is an indication of what happens when you try to do too much using a common abstraction like Lens. These general abstractions are good for some general purpose, and everything else depends on your problem and should be designed around simple old functions (at least initially, in the future in your project you can find a general template in your code base, which you can abstract using class types, etc.).

+2
source

Some comments on your problem:

The answer to the question : Perhaps you can do what you want. The lens library is amazingly versatile. What does not exist is a simple or obvious way to do this. I think this will include partsOf combinator , but I'm not sure.

Comments on lenses : The lens library is really cool and can be applied to many problems. My initial temptation when I was studying the library was to try to fit everything into lens access or mutation. I found it better to use a lens library to delve into my complex data structures, but as soon as I had a simple element, it was better to use more traditional functional methods that I already knew, and then stretch the lens library, limit.

Tip that you did not request : Inserting an element in the middle of the list is a bad idea. Not that this cannot be done, but ultimately it may be operation O (n ^ 2). ( fooobar.com/questions/34817 / ... ) Zip lists or some other functional data structure might be a better idea. As a side benefit, some of these structures could be made into an instance of the At class, allowing partial lenses to insert and remove using combinators.

+2
source

Source: https://habr.com/ru/post/952634/


All Articles