Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.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
Reference 在哈希表中记录函数_Reference_Ocaml_Memoization - Fatal编程技术网

Reference 在哈希表中记录函数

Reference 在哈希表中记录函数,reference,ocaml,memoization,Reference,Ocaml,Memoization,我必须完成一个练习,其中 我编写了一个函数memo:(('a->'b)->'a->'b)->stats->'a->'b.函数memo将函数f(我们要记忆的函数)作为输入,记录stats类型(其类型声明如下所示),以跟踪我们访问本地存储的频率和添加的条目数量,并返回类型为“a->”b的函数 当使用“a”类型的输入调用此函数时,它将运行f,记录中间结果,并作为最终结果返回“b”类型的值。它还将相应地更新其stats记录中的值。例如,要创建一个将数字累加到x的memoizing函数,我们有memo(f

我必须完成一个练习,其中

我编写了一个函数memo:(('a->'b)->'a->'b)->stats->'a->'b.函数memo将函数f(我们要记忆的函数)作为输入,记录stats类型(其类型声明如下所示),以跟踪我们访问本地存储的频率和添加的条目数量,并返回类型为“a->”b的函数

当使用“a”类型的输入调用此函数时,它将运行f,记录中间结果,并作为最终结果返回“b”类型的值。它还将相应地更新其stats记录中的值。例如,要创建一个将数字累加到x的memoizing函数,我们有memo(fungx->如果x=0,那么0 else x+g(x-1))stats

记录类型统计信息有两个字段:

条目:已记录的结果数

lkp:在存储中找到已记忆结果而不是执行函数的次数

注意给定函数f的类型:它本身需要另一个函数作为参数。具体来说,传递给f的函数g将是f在递归情况下调用的函数

我遇到的问题是,我的查找次数总是减少1或2次。如果有人能澄清为什么会发生这种情况或给我一个提示,我将不胜感激。下面是我的尝试,它计算函数调用的正确值和正确的条目数。希望下面的代码能让它更清晰:

type stats =
  { entries : int ref;
    lkp : int ref }

let memo (f: (('a -> 'b) -> 'a -> 'b)) (stats: stats) : ('a -> 'b) =

  let map = Hashtbl.create 1000 in
  let rec g x =
    match Hashtbl.find_opt map x with
    | None -> let result = f (g) x in Hashtbl.add map x result ; stats.entries := !(stats.entries) + 1 ; result
    | Some v -> stats.lkp := !(stats.lkp)+ 1 ; v 
  in stats.entries := !(stats.entries) + 1 ; f g

让我们对您的代码进行除臭:

type stats = {
  entries : int ref;
  lkp : int ref
}

let memo (f: (('a -> 'b) -> 'a -> 'b)) (stats: stats) : ('a -> 'b) =
  let map = Hashtbl.create 1000 in
  let rec g x =
    match Hashtbl.find_opt map x with
    | None ->
      let result = f (g) x in
      Hashtbl.add map x result;
      incr stats.entries;
      result
    | Some v ->
      incr stats.lkp;
      v in
  incr stats.entries;
  f g
现在,我们可以很容易地看到,如果我们有一个缓存未命中(
None
分支),我们会增加条目的数量(看起来正确),但不会增加查找的数量(看起来可疑,我仍然会将其视为一个查找,除非您所说的查找是指缓存命中)。当缓存命中(Some分支)时,我们会增加查找次数。到现在为止,一直都还不错。我们还可以看到,出于某种原因,在调用
memo
时,我们无条件地增加了条目数。这看起来很奇怪,我们没有在这里添加任何条目。很可能是一些遗留代码


我希望剩下的都清楚了。主要的好处是,您应该尝试编写语法上易于理解的程序。不要害怕使用键盘上的回车键,不要试图一次做太多。另外,尝试使用支持自动缩进的IDE(vscode、emacs、vim)。这会让你免于令人不快的惊喜。

谢谢,这看起来比我的好多了。我无条件地增加stats.entries,因为出于某种原因,当函数调用完成时,它似乎给了我正确的条目数,尽管我同意这没有意义。再加上我的查找次数比应该的多1或2,使我觉得有些案例没有被正确缓存,但我不确定。尽管缺少
incr stats.lkp
在miss case(None分支)中,我看不到您的代码有任何问题,当我运行它时,我得到了我期望的数字。啊,好的,不管怎样,还是要谢谢你的时尚提示。我在最后一行中用“g”替换了“fg”,并删除了最后一行中多余的增量操作,从而解决了我的问题。实际上,我认为在这种情况下,用g代替fg不会有什么不同,但令人惊讶的是did@JeffreyScofield,我认为您在错误的帖子中发布了一条评论:)(评论还可以,但代码现在已更正。)请不要修改问题,使现有答案无效。