Scala 有没有通用的记忆方法?

2024-01-12

我想记住这一点:

def fib(n: Int) = if(n <= 1) 1 else fib(n-1) + fib(n-2)
println(fib(100)) // times out

所以我写了这个,令人惊讶的是,它编译并工作了(我很惊讶,因为fib在其声明中引用自身):

case class Memo[A,B](f: A => B) extends (A => B) {
  private val cache = mutable.Map.empty[A, B]
  def apply(x: A) = cache getOrElseUpdate (x, f(x))
}

val fib: Memo[Int, BigInt] = Memo {
  case 0 => 0
  case 1 => 1
  case n => fib(n-1) + fib(n-2) 
}

println(fib(100))     // prints 100th fibonacci number instantly

但是当我尝试在 a 中声明 fib 时def,我收到编译器错误:

def foo(n: Int) = {
  val fib: Memo[Int, BigInt] = Memo {
    case 0 => 0
    case 1 => 1
    case n => fib(n-1) + fib(n-2) 
  }
  fib(n)
} 

以上无法编译error: forward reference extends over definition of value fib case n => fib(n-1) + fib(n-2)

为什么要声明val fib在 def 内部失败,但在类/对象范围之外有效?

为了澄清,为什么我可能想在 def 范围中声明递归记忆函数 - 这是我对子集和问题的解决方案:

/**
   * Subset sum algorithm - can we achieve sum t using elements from s?
   *
   * @param s set of integers
   * @param t target
   * @return true iff there exists a subset of s that sums to t
   */
  def subsetSum(s: Seq[Int], t: Int): Boolean = {
    val max = s.scanLeft(0)((sum, i) => (sum + i) max sum)  //max(i) =  largest sum achievable from first i elements
    val min = s.scanLeft(0)((sum, i) => (sum + i) min sum)  //min(i) = smallest sum achievable from first i elements

    val dp: Memo[(Int, Int), Boolean] = Memo {         // dp(i,x) = can we achieve x using the first i elements?
      case (_, 0) => true        // 0 can always be achieved using empty set
      case (0, _) => false       // if empty set, non-zero cannot be achieved
      case (i, x) if min(i) <= x && x <= max(i) => dp(i-1, x - s(i-1)) || dp(i-1, x)  // try with/without s(i-1)
      case _ => false            // outside range otherwise
    }

    dp(s.length, t)
  }

我找到了一种使用 Scala 进行记忆的更好方法:

def memoize[I, O](f: I => O): I => O = new mutable.HashMap[I, O]() {
  override def apply(key: I) = getOrElseUpdate(key, f(key))
}

现在您可以如下编写斐波那契数:

lazy val fib: Int => BigInt = memoize {
  case 0 => 0
  case 1 => 1
  case n => fib(n-1) + fib(n-2)
}

这是一个具有多个参数的函数(选择函数):

lazy val c: ((Int, Int)) => BigInt = memoize {
  case (_, 0) => 1
  case (n, r) if r > n/2 => c(n, n - r)
  case (n, r) => c(n - 1, r - 1) + c(n - 1, r)
}

这是子集和问题:

// is there a subset of s which has sum = t
def isSubsetSumAchievable(s: Vector[Int], t: Int) = {
  // f is (i, j) => Boolean i.e. can the first i elements of s add up to j
  lazy val f: ((Int, Int)) => Boolean = memoize {
    case (_, 0) => true        // 0 can always be achieved using empty list
    case (0, _) => false       // we can never achieve non-zero if we have empty list
    case (i, j) => 
      val k = i - 1            // try the kth element
      f(k, j - s(k)) || f(k, j)
  }
  f(s.length, t)
}

编辑:如下所述,这是一个线程安全版本

def memoize[I, O](f: I => O): I => O = new mutable.HashMap[I, O]() {self =>
  override def apply(key: I) = self.synchronized(getOrElseUpdate(key, f(key)))
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 有没有通用的记忆方法? 的相关文章

随机推荐

  • ASP.NET 路由是否可用于为 .ashx (IHttpHander) 处理程序创建“干净”的 URL?

    我有一些使用普通旧式的 REST 服务IHttpHandlers 我想生成更清晰的 URL 这样路径中就没有 ashx 有没有办法使用 ASP NET 路由来创建映射到 ashx 处理程序的路由 我以前见过这些类型的路线 Route to
  • 如何在sql中选择连续日期

    是否有任何函数可以检查连续日期 我在处理以下问题时遇到问题 我的桌子上有一个datetime包含以下数据的列 2015 03 11 2015 03 12 2015 03 13 2015 03 16 指定开始日期为2015 3 11和结束日期
  • FireBase API 是否有未缩小的 JavaScript 版本?

    我正在为通过 FireBase 提供 API 的设备开发一个界面 但我没有使用 Java JavaScript 或 FireBase 提供的库的任何其他语言 我正在使用 Lua 虽然我可以轻松实现 REST API 但我希望能够使用 Fir
  • Google APIs Explorer 未从我的应用程序引擎应用程序中找到可用的 ApiMethod

    我有一个可以正常编译的 App Engine 应用程序 我使用本地主机上的 Google Apis Explorer 测试方法调用 https developers google com apis explorer base http lo
  • 临时表在同一连接池上的多个请求中是否唯一?

    我有以下存储过程 它使用临时表批量导入数据 我知道临时表对于每个会话都是唯一的 但是我想知道我的应用程序是否使用线程并向存储过程发出多个并发请求 使用应用程序池中的相同 sql 连接 它们最终会引用相同的临时表吗 CREATE PROCED
  • Rhino - 将 javascript 对象传递给 java

    我对 Rhino 很陌生 我的问题是如何实现以下目标 假设我有一个 javascript 对象 它遵循如下所示的内容 我可以在 java 中使用它 var myObject new Object myObject string1 Hello
  • 没有jquery的自定义滚动条

    我正在寻找一个无需 jquery 即可工作的自定义滚动条 我不能使用 jquery 因为其他东西也是无 jquery 的 并且它针对快速加载进行了优化 将不胜感激与我分享的任何想法 NONNNNN 如果您不想使用 jQuery 您可以随时尝
  • 正则表达式正在抓取前面的字符

    所以我在正则表达式中遇到了一些不一致的行为 我的正则表达式 lt test 输入字符串 test exe c echo teststring gt test teststring 当我运行这个时https Regex101 com http
  • 自 UTC 时区当天开始以来的秒数

    如何在Python中找到 自UTC时区开始以来的秒数 我查看了文档 但不明白如何使用它datetime timedelta 这是一种方法 from datetime import datetime time utcnow datetime
  • 设置selectedindex不触发onchange事件

    我正在尝试更改选择标签的选定索引 但是通过 jquery 更改索引时不会触发 onchange 事件 我正在动态地为选择标签创建选项 我不会知道选项标签的值 还有其他方法可以实现吗 这是我的代码片段 请随意提供意见 function cal
  • 如何让 Pyflakes 忽略语句?

    我们的许多模块都是从以下开始的 try import json except ImportError from django utils import simplejson as json Python 2 4 fallback 这是整个文
  • 获取 Haskell CSV 中的列并推断列类型

    我正在交互式 ghci 会话中探索 csv 文件 在 jupyter 笔记本中 import Text CSV import Data List import Data Maybe dat lt parseCSVFromFile home
  • 如何从我的应用程序中打开 iPhone 日历?

    我希望能够在我的应用程序中实现一个按钮 用于退出我的应用程序 并将用户带到 iPhone 的日历 我对将用户发送到特定事件不感兴趣 只要打开日历就可以了 有什么建议么 嘿可能是一个迟到的答案 但你现在可以这样做 UIApplication
  • ExtJS 4 关联和 store.save()

    我正在使用 ExtJS 4 并且有一个定义了关联 hasMany 的模型 ModelA gt hasMany gt ModelB 我使用 GridA 显示来自 ModelA 的数据 单击 GridA 中的记录时 我使用 rowSelect
  • 使用jquery进行反应以滑动切换

    我正在尝试通过制作带有可折叠项目的菜单来学习一些 React 我使用 jQuery 来实现它的 SlideToggle 功能 但我无法让它正常工作 反应代码的相关部分是这样的 var CollapsableMenuItem React cr
  • 在react-native-web中使用flex布局复制/粘贴

    我有一个通过 React Native 和 React Native Web 在本机和 Web 上运行的应用程序 一个屏幕包含一个带有自定义项目符号的列表 如下图所示 尽管文本通常会长到多行 问题是 当您复制 粘贴 至少在网络上 时 项目符
  • jquery 承诺的延迟

    我找不到delay or wait函数为jQuery承诺 我在 SO 上找到了一项功能 使用 jQuery Deferred 避免嵌套 setTimeout 回调 https stackoverflow com q 17983331 104
  • 用户如何在客户端下载文件(Google Web Toolkit)

    我正在使用 GWT Google Web Toolkit 制作一个网站 我需要向用户显示一个表格 并让用户下载表格的内容 在客户端 用户按下 下载 按钮时如何下载文件 下载 按钮有一个onClick 听众 并且客户端类扩展Composite
  • 外部声明中的警告

    include
  • Scala 有没有通用的记忆方法?

    我想记住这一点 def fib n Int if n lt 1 1 else fib n 1 fib n 2 println fib 100 times out 所以我写了这个 令人惊讶的是 它编译并工作了 我很惊讶 因为fib在其声明中引