F#:是否可以使用可变的 .Net List 将元素添加到同一列表
F# : Is it okay to use mutable .Net List to add elements to the same list
在一个循环中,我将一个新元素添加到我在下一次迭代中需要的列表中,为此我使用了可变的 .Net List<T>
.
F#
鼓励一般使用不可变集合,似乎我无法使用不可变 list
或 seq
.
实现我想要的
继续使用可变的 .Net List<T>
是可以接受的,还是鼓励只使用不可变的?如果可以,我该如何实现?
我的代码有点长和复杂,所以让我们考虑一下这个伪 F# 代码:
let children = new List<node>()
let bestBranchEntropies = entropiesSuchAs data.Rows parents
//Finding the best children for the best parent
bestBranchEntropies |> Seq.iter (fun bestBranch -> let attribut = IGetTheAttributByMaximumGainHere
//Creating one of the children in every iteration
let node = {
content = attribut;
branch = Some(fst bestBranch);
children = None;
isLeaf = false;
}
//Considering it a child
children.Add node
)
//After having all the children
let children' = children |> Seq.map (fun child -> {
content = child.content;
branch = child.branch;
children = //recursive call here to do the same work above (getting children again, yeah it's a tree)
isLeaf = child.isLeaf;
})
Some(children')
据我所知,当然不需要可变列表(如果您的伪代码完全反映了问题)。考虑以下因素:
let children =
bestBranchEntropies
|> Seq.map (fun bestBranch ->
let attribut = IGetTheAttributByMaximumGainHere
//Creating one of the children in every iteration
{
content = attribut;
branch = Some(fst bestBranch);
children = None;
isLeaf = false;
}
|> Seq.toList
children
|> Seq.map (fun child ->
{
content = child.content
branch = child.branch
children = //recursive call here to do the same work above (getting children again, yeah it's a tree)
isLeaf = child.isLeaf
}
)
|> Some
第一个 Seq.toList
可以跳过,您可以一直使用管道。从你的伪代码看来,整个第二个循环实际上可以安全地与第一个循环合并?
从你的伪代码看不是很清楚,但我知道你问的真正问题是"can I use a mutable list instead of an accumulator when traversing a tree structure?"。
我觉得没问题,前提是:
- 可变对象是函数的本地对象,不能以其他方式访问和篡改,
- 它的目的用注释清楚地标明了,这样未来的维护者在重构代码时就不会被它绊倒(并且错误地假设可变对象是不可变的)。
它确实节省了为树编写适当的尾递归 fold
所需的大量时间(这当然也是一个选项,请参阅 this blog post series)。即使您最终写了一个 fold,首先对您的方法进行原型设计也是一个不错的选择。
作为旁注,我更喜欢使用 ref cells + 不可变集合而不是可变集合来达到这个目的。与在可变列表上调用 Add
相比,改变引用单元格所需的额外语法使它非常清楚发生了什么。
在一个循环中,我将一个新元素添加到我在下一次迭代中需要的列表中,为此我使用了可变的 .Net List<T>
.
F#
鼓励一般使用不可变集合,似乎我无法使用不可变 list
或 seq
.
继续使用可变的 .Net List<T>
是可以接受的,还是鼓励只使用不可变的?如果可以,我该如何实现?
我的代码有点长和复杂,所以让我们考虑一下这个伪 F# 代码:
let children = new List<node>()
let bestBranchEntropies = entropiesSuchAs data.Rows parents
//Finding the best children for the best parent
bestBranchEntropies |> Seq.iter (fun bestBranch -> let attribut = IGetTheAttributByMaximumGainHere
//Creating one of the children in every iteration
let node = {
content = attribut;
branch = Some(fst bestBranch);
children = None;
isLeaf = false;
}
//Considering it a child
children.Add node
)
//After having all the children
let children' = children |> Seq.map (fun child -> {
content = child.content;
branch = child.branch;
children = //recursive call here to do the same work above (getting children again, yeah it's a tree)
isLeaf = child.isLeaf;
})
Some(children')
据我所知,当然不需要可变列表(如果您的伪代码完全反映了问题)。考虑以下因素:
let children =
bestBranchEntropies
|> Seq.map (fun bestBranch ->
let attribut = IGetTheAttributByMaximumGainHere
//Creating one of the children in every iteration
{
content = attribut;
branch = Some(fst bestBranch);
children = None;
isLeaf = false;
}
|> Seq.toList
children
|> Seq.map (fun child ->
{
content = child.content
branch = child.branch
children = //recursive call here to do the same work above (getting children again, yeah it's a tree)
isLeaf = child.isLeaf
}
)
|> Some
第一个 Seq.toList
可以跳过,您可以一直使用管道。从你的伪代码看来,整个第二个循环实际上可以安全地与第一个循环合并?
从你的伪代码看不是很清楚,但我知道你问的真正问题是"can I use a mutable list instead of an accumulator when traversing a tree structure?"。
我觉得没问题,前提是:
- 可变对象是函数的本地对象,不能以其他方式访问和篡改,
- 它的目的用注释清楚地标明了,这样未来的维护者在重构代码时就不会被它绊倒(并且错误地假设可变对象是不可变的)。
它确实节省了为树编写适当的尾递归 fold
所需的大量时间(这当然也是一个选项,请参阅 this blog post series)。即使您最终写了一个 fold,首先对您的方法进行原型设计也是一个不错的选择。
作为旁注,我更喜欢使用 ref cells + 不可变集合而不是可变集合来达到这个目的。与在可变列表上调用 Add
相比,改变引用单元格所需的额外语法使它非常清楚发生了什么。