Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 不是解析/计算值,而是保存函数?因此,解析只发生一次_F# - Fatal编程技术网

F# 不是解析/计算值,而是保存函数?因此,解析只发生一次

F# 不是解析/计算值,而是保存函数?因此,解析只发生一次,f#,F#,我正在尝试实现类似电子表格的功能,它维护变量,并在其他变量或“单元格”更改时正确更新它们 到目前为止,我看到的唯一一个实现是将输入的数据存储在字符串中并对其求值,但是当数据更改和单元格需要重新计算时,它总是需要再次对字符串求值 我只是想知道是否有可能将像Cell1=“SQUARED(4)”这样的字符串解析为Cell1=SQUARED 4 因此,它不需要将值计算到单元格中,而是需要在需要重新计算时反复运行字符串,而是可以将实际函数和值以某种方式保存在某个位置,这样解析和计算只需进行一次 如果这是不

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

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

我只是想知道是否有可能将像Cell1=“SQUARED(4)”这样的字符串解析为Cell1=SQUARED 4 因此,它不需要将值计算到单元格中,而是需要在需要重新计算时反复运行字符串,而是可以将实际函数和值以某种方式保存在某个位置,这样解析和计算只需进行一次

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


所以这首先只是一个是或不是的问题。如果可能的话,任何例子当然都会有帮助。编辑:嗯,我想这会很有帮助,因为我自己也不知道这个问题。

唐·赛姆关于备忘录的博客中有一个很好的例子-

你写这个函数

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

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

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

  • 其次,Luca Bolognese讨论了称为“Eden”的计算框架的实现,在该框架中,您用单元格来描述计算,当单元格中的值发生变化时,变化会自动传播(并且只重新计算相关单元格)。他将在会议上发言,但我认为这已经被记录在某处(但找不到)

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

type Cell<'T> =
  abstract Value : 'T  
  abstract Changed : IEvent<unit>
然后,您还可以构造作为某些计算结果生成的单元。这是一个演讲或博客文章的主题,不是一个简单的答案,但将单元格中的值映射到另一个单元格的简单转换如下所示:

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 }
let映射f(单元格:单元格)=
让currentValue=ref(f cell.Value)
cell.Changed.Add(fun()->currentValue:=f cell.Value)
{带有
成员x.Value=当前值.Value
成员x.Changed=cell.Changed}

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

哇,这太快了!如果这真的是答案,那么哇,谢谢你!我可能需要一些时间才能更好地理解这一点,因此我将很快报告:)为了确保我们的意见一致,我不会一次又一次地计算所有单元格,只有当它们需要更新时,才会通知它们,并且现在重新计算字符串,但我希望它只是再次运行其函数。这有帮助吗因为我一直在读维基百科,我不确定这是我需要的。@user1594138这个想法是说你有:
let evaluate cell=..
你写
let m_evaluate=memoize evaluate
,然后如果你重复输入调用
m_evaluate
,你可以从缓存中获取一个值,而不必重新评估你的函数。是的,但是只有在需要更新的情况下才会更新,这意味着某些东西已经改变了。所以,也许我在我的帖子中给出了一个不好的例子,但大多数单元格都是基于其他单元格的,只有当通知其他单元格发生了变化时,才会更新此单元格所依赖的单元格。所以Cell1=cell2+cell3,Cell1仅在cell2或cell3发生变化时更新。因此,虽然它是同一个字符串cell1=“cell2+cell3”,但数据发生了变化。我只是想让它保存函数而不是字符串,所以Cell1=cell2+cell3,就像你用纯代码编写它一样。你至少可以保存部分工作-只有两个阶段-第一阶段从
string->'t
开始,其中
't
是某种计算速度相当快的数据类型-也可以存储依赖项,但你必须重复计算fast函数。不过,我建议你还是先试试天真版吧——在现代硬件上,它可能足够快。谢谢你的帮助,但我认为我的问题写得不够好,因为我知道所有这些。我已经看过cellz的源代码,并且非常了解它,这正是我想问的那种风格,是否可以不这样做。它的问题正是我键入的内容,它调用整个计算/解析函数,以及每次需要重新计算单元格时的所有开销。我要问的是,这是否可以跳过,解析器只是将值设置为如何在实际代码中编写它。所以cell1=cell2+1,而不是cell1=计算“cell2+1”,所以它只是以某种方式计算cell1等于cell1=cell2+1。看起来这是不可能的,我只需要创建一个代码生成器。因此,我只需输入Cell1=cell2+1,它将以普通代码创建对象、单元格条目、依赖项等,除了在代码生成器中生成代码外,不进行任何计算。抱歉,尽管这可能是一个非常愚蠢的问题,但我不知道什么是可能的,什么是不可能的。我想我会简单地创建一个代码生成器,让事情尽可能地高效,谢谢你的帮助!FSharp
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
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 }