【问题标题】:Confusion on "Immutable" lists in F#F# 中“不可变”列表的困惑
【发布时间】:2020-11-04 19:19:46
【问题描述】:

完全是新手问题。

我仍在尝试掌握 F# 中的“不可变”列表。

假设我有一个“访问”定义为:

module Visit =
    type Model =
        {
            Name: string
        }

    let init row col cel =
        { 
            Name = sprintf "My Name is row: %d col: %d  cel: %d" row  col cel       
        }

现在我定义一个“单元”,它可能会访问一次,也可能不会访问:

module Cell =
    type Model =
        {
            Visit: Visit.Model option
        }

    let setVisit m =
        { m with Visit = Some( Visit.init 9 9 9) }

最后我定义了一个包含单元格列表的“列”:

module Column =
    type Model =
        {         
            Appointments: Cell.Model list
        }


    let updateCell (m:Model) =
        let newList = m.Appointments |> List.mapi (fun index cell -> if index = 2 then Cell.setVisit cell else cell)
        {m with Appointments = newList }

在 Column 模块中,“updateCell”函数被连接为调用第 3 个单元格的 Cell.setVisit。我的意图是替换第 3 个单元格持有的“访问”的“名称”。我的简单问题是:

  1. 这是正确的方法吗?
  2. 如果我要替换约会列表,这不会改变保存约会列表的“列”吗? (Column 是不可变的,对吧?)。

对不起,我的困惑。

TIA

【问题讨论】:

  • 我想说,如果您正在学习函数式编程,请尝试使用不可变的数据结构来做到这一点,从而重新连接您的大脑,使其以这种方式思考。如果您真的需要这些额外的 pico 秒,那么可以,使用数组,或者您可以开始研究纯粹的替代方案。

标签: f#


【解决方案1】:

首先:是的,这是一种可以接受的方法,但对列表来说效率低下。请注意,您在每次调用 updateCell 时都会重建整个列表,即使其中的大多数元素都是相同的。

我不知道在实践中您希望在您的模型中进行多少次约会。如果它明显多于三个,并且您总是更新第三个,那么剪切列表然后将其重新粘在一起会更有效:

let newList = List.take 2 m.Appointments @ [Cell.setVisit m.Appointments.[2]] @ List.drop 3 m.Appointments

这种方式只重建前三个元素,并重用列表的尾部。

但是,如果您需要随机访问操作,我可以建议使用数组吗?当然,它们是可变的,但它们为随机访问操作提供了更好的性能。

第二:不,{ m with ... } 的语法不会改变Column。相反,它会创建一个 列 - m 的副本,但在 with 之后列出的所有字段都更新为新值。

【讨论】:

  • 谢谢。我不知道“m with ...”语法确实会创建一个新列。这可以解释很多。是的,最终我需要随机访问,并且可能有多达 160 个约会。再次感谢。
  • @ 符号在做什么?我以前没见过。
  • @ 连接列表
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多