使用镜头插入特定位置的列表中 [英] Inserting into a list at a specific location using lenses

查看:91
本文介绍了使用镜头插入特定位置的列表中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对包含元素列表的嵌套数据结构进行操作.经过各种方法的摸索之后,我最终选择了镜片作为实现此目的的最佳方法.它们非常适合查找和修改结构的特定元素,但是到目前为止,我对如何添加新元素感到困惑.

I'm trying to perform a manipulation of a nested data structure containing lists of elements. After mucking around with various approaches I finally settled on lenses as the best way to go about doing this. They work perfectly for finding and modifying specific elements of the structure, but so far I'm stumped on how to add new elements.

根据我的阅读,从技术上讲,我不能使用遍历,因为它违反了遍历律,无法在列表中插入新元素,并且假设我什至可以弄清楚如何在遍历中使用遍历.第一名(我对Haskell仍然很虚弱,并且镜头包装中大多数东西的类型签名使我头晕目眩).

From what I've read, I can't technically use a Traversal as it violates the Traversal laws to insert a new element into a list, and that's assuming I could even figure out how to do that using a Traversal in the first place (I'm still fairly weak with Haskell, and the type signatures for most things in the lens package make my head spin).

具体来说,我要完成的工作是,在元素列表中找到与特定选择器匹配的某个元素,然后在匹配的元素之前或之后插入一个新元素(此函数之前或之后的函数的不同参数)或比赛结束后). Control.Lens是否已经可以完成我想做的事情,而我对类型签名的理解太薄弱,看不到它?有没有更好的方法可以完成我想做的事情?

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

如果我只是想在列表的开头或结尾添加一个新元素,那将是微不足道的,但是将其插入中间特定的位置是困难的部分.在我写的一些镜头前代码中,我使用了折叠来完成我想要的东西,但是它开始在结构的更深层嵌套的部分上变得粗糙(例如,折叠内部是折叠内部)我转向Control.Lens尝试解开一些混乱.

It would be fairly trivial if I was just trying to add a new element either to the beginning or the end of a list, but inserting it somewhere specific in the middle is the difficult part. In some of the pre-lens code I wrote I used a fold to accomplish what I wanted, but it was starting to get gnarly on the more deeply nested parts of the structure (E.G. a fold inside of a fold inside of a fold) so I turned to Control.Lens to try to untangle some of that mess.

推荐答案

使用镜头 pacakge

Using lens pacakge

如果我们首先知道函数id可以像镜头一样使用:

If we start with knowing the function id can be used like 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 modified:

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

以上内容允许在列表的开头插入.为了专注于列表的后半部分,我们可以使用 _tail 来自

The above allows for insertion at the start of the list. To focus on the latter 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]

现在将其推广到第n个位置

Now to generalize this for 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]

使用 Cons实例,我们可以使用cons<|.

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

这篇关于使用镜头插入特定位置的列表中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆