2

我正在尝试实现类似电子表格的功能,它维护变量并在其他变量或“单元格”发生变化时正确更新它们。

到目前为止,我看到的唯一实现是将输入的数据存储在字符串中并对其进行评估,但是当数据更改并且需要重新计算单元格时,它总是需要再次评估字符串。

我只是想知道是否有可能将像 Cell1 = "SQUARED (4)" 这样的字符串解析为 Cell1 = squared 4 所以不是将值计算到单元格中,而是需要再次运行字符串并且再次,当需要重新计算时,它可以以某种方式在某处保存实际的函数和值,以便解析和评估只需要发生一次。

如果这不可能,那么我需要创建一个代码生成器,因为我需要速度非常快并且不能承受严重的性能损失。评估、编译等的速度并不重要。当输入数据更改数百万次并通过类似系统的“电子表格”传播时,这是创建所有单元格后的速度。

所以这首先只是一个是或否的问题。如果可能的话,任何示例当然都会有所帮助。编辑:好吧,我想这真的很有帮助,因为我自己无法弄清楚。

4

2 回答 2

3

如果您对实现电子表格之类的东西感兴趣,那么有两件事可能会有所帮助。

  • 首先,Cellz 项目是 F# 中电子表格的示例实现。它包括一个简单的字符串解析器,如“=SUM(A1:A10)”,并从这些字符串构建一个表达式树(只完成一次)。其次,它还包括一个计算表达式值的求值器。

  • 其次,Luca Bolognese 对名为“Eden”的计算框架的实现进行了几次讨论,您在其中描述了单元格的计算,当单元格中的值发生变化时,变化会自动传播(并且仅重新计算相关单元格)。他将在TechMesh London 2012上发表演讲,但我认为这已经记录在某个地方(但找不到)。

Eden 背后的基本思想是将单元格表示为具有当前值和在值更改时触发的事件的东西:

type Cell<'T> =
  abstract Value : 'T  
  abstract Changed : IEvent<unit>

显式创建和变异的单元格具有可变性Value,并在用户更改值时触发事件:

type MutableCell<'T>(value:'T) = 
  let mutable currentValue = value
  let event = Event<unit>()
  member x.Value 
    with get() = currentValue
    and set(v) = 
        currentValue <- v
        event.Trigger()
  interface Cell<'T> with 
    member x.Value = currentValue
    member x.Changed = event.Publish

然后,您还可以构建由于某些计算而产生的单元格。这是演讲或博客文章的主题,而不是 SO 答案,但是将单元格中的值映射到另一个单元格的简单转换如下所示:

let map f (cell:Cell<_>) =
  let currentValue = ref (f cell.Value)
  cell.Changed.Add(fun () -> currentValue := f cell.Value) 
  { new Cell<_> with
      member x.Value = currentValue.Value
      member x.Changed = cell.Changed }

您需要能够组合来自多个单元格等的值。

于 2012-11-02T12:58:21.427 回答
2

Don Syme 的关于记忆的博客中有一个很好的例子 - https://blogs.msdn.com/b/dsyme/archive/2007/05/31/a-sample-of-the-memoization-pattern-in-f .aspx?重定向=真

你写这个函数

let memoize f =
    let cache = Dictionary<_, _>()    
    fun x ->    
        if cache.ContainsKey(x) then cache.[x]    
        else let res = f x    
             cache.[x] <- res    
             res

然后你可以创建一个记忆函数,如:

let memoizedAppend =
    memoize (fun input ->
        printfn "Working out the value for '%A'" input
        String.concat ", " [ for i in 0 .. 9 -> sprintf "%d: %s" i input ])
于 2012-11-02T11:04:21.993 回答