如何在 Nim 中缓存具有不同参数的函数?

How to cache function with different arguments in Nim?

我正在使用缓慢的数据加载和计算,并且想缓存结果,所以下次它会更快。

示例 - 我们想要两个功能 1) 将货币转换为美元和 2) 计算 CPI 指数(消费者价格指数)。

echo to_usd("EUR", (2000, 1, 1), false) # => 0.846
echo to_cpi("USD", (2000, 1, 1))        # => 144.0

我想知道是否可以自动生成缓存代码,也许可以使用一些库?类似于:

proc to_usd_slow*(currency: string, time: TimeD): float =
  1.0 # some slow calculations

proc to_usd* = cache(to_usd_slow)

我目前正在手动写入缓存,如下面的代码所示,playground:

import hashes, tables

proc autohash*[T: tuple|object](o: T): Hash =
  for f in o.fields: result = result !& f.hash

type
  TimeD = tuple[year, month, day: int]
  PointM = tuple[time: TimeD, value: float]

# CPI - Consumer Price Index
proc to_cpi_slow(currency: string, time: TimeD, extrapolate: bool): float =
  1.0 # some slow calculations

# Cached version ---------------------------------------------------------------
type ToCpiKey = (string, TimeD, bool)
proc hash(v: ToCpiKey): Hash = v.autohash
var to_cpi_cache = init_table[ToCpiKey, float]()

proc to_cpi*(currency: string, time: TimeD, extrapolate: bool): float =
  let key: ToCpiKey = (currency, time, extrapolate)
  if key notin to_cpi_cache:
    to_cpi_cache[key] = to_cpi_slow(currency, time, extrapolate)
  to_cpi_cache[key]

# Curency conversions ----------------------------------------------------------
proc to_usd_slow*(currency: string, time: TimeD): float =
  1.0 # some slow calculations

type ToUsdMKey = (string, TimeD)
proc hash(v: ToUsdMKey): Hash = v.autohash

var to_usd_cache = init_table[ToUsdMKey, float]()
proc to_usd*(currency: string, time: TimeD): float =
  let key: ToUsdMKey = (currency, time)
  if not(key in to_usd_cache): to_usd_cache[key] = to_usd_slow(currency, time)
  to_usd_cache[key]

# Usage ------------------------------------------------------------------------
echo to_cpi("USD", (2000, 1, 1), false)
echo to_usd("EUR", (2000, 1, 1))

可以使用宏生成缓存代码,很可能您想寻找 macro pragmas 来为您的函数编写必要的样板文件。

如果您想使用现有的库,您可能需要查看 memo 库。