【问题标题】:Is there any way to memoize a value in Haskell?有没有办法在 Haskell 中记住一个值?
【发布时间】:2011-11-04 20:20:09
【问题描述】:

我在 Haskell 中有以下功能:

memdb = -- load the contents of a database into memory as a Map

然后我有以下行:

map (\x -> memdb ! x) values

我希望 memdb 只生成一次 Map,而不是在 map 的每次迭代中生成。我可以这样做:

make_memdb = -- equivalent to memdb in previous example
memdb <- make_memdb
map (\x -> memdb ! x) values

但这意味着我必须将memdb 传递给每个使用它的函数。有什么办法可以:

一个。避免在每次调用时重新计算memdb OR

b.将make_memdb 中生成的值保存为常量,这样我就可以避免将它传递给每个使用它的函数?

【问题讨论】:

  • @Craig Stuntz:在发布我的问题之前,我已经阅读了这个问题。这些答案将如何帮助我实现一个。或 b。 ?
  • @Craig:尽管有标题,但这个问题实际上并不是通常意义上的记忆。这不是那个问题的重复。

标签: haskell functional-programming memoization


【解决方案1】:

由于您的地图来自数据库,这意味着它不能是常数,因为它在您的应用程序运行之间可能会有所不同。

但这意味着我必须将 memdb 传递给每个使用它的函数。

是的,但是有一些工具可以让这件事变得不像听起来那么糟糕。特别是,这听起来像是 the reader monad! 的完美用例!

Reader monad 通常在您有一些价值(例如配置)时使用,您希望在程序开始时加载它,然后能够在您的程序中访问它,而无需一直显式地传递它。下面是一个简短的示例,说明您将如何使用它:

main = do
    memdb <- make_memdb -- Get the memdb from the database once and for all
    runReaderT foo memdb

foo = do
    memdb <- ask -- Grab the memdb. Will not reload from the database
    liftIO $ putStrLn "Hello, world" -- IO actions have to be lifted
    -- [...]

另见:

【讨论】:

  • 这个问题几乎是提出来向读者单子宣传的。很好的答案。
【解决方案2】:

您似乎想通过IO 获得memdb 作为避免传递更多参数的一种方式,对吗?然后你问你是否可以(A)定义memdb,暗示它将是一个顶级函数,没有从数据库加载数据的开销,或者(B)你是否可以保存加载的全局范围的数据结构。

这两者都可以使用IORefunsafePerformIO 来定义顶级可变全局变量。我不建议你这样做。重构既笨拙又烦人。话虽如此,我还是会告诉你怎么做:

假设你有一个函数:

make_memdb :: IO (Map K V)

你可以声明一个顶级的可变变量:

import Data.Map as M
import Data.IORef

mRef :: IORef (Map K V)
mRef = unsafePerformIO $ newIORef M.empty
{-# NOINLINE mRef #-}

main = do
    m <- make_memdb
    writeIORef mRef m
    ... do  stuff using mRef ...

stuffUsingMRef ... = do
    memdb <- readIORef
    let vs = map (memdb !) values
    return vs

请注意,您的函数将永远存在于IO。这是因为您需要IO 才能读取您放置memdb 的全局可变变量。如果你不喜欢这样,也不喜欢传递参数,那就学习 state monad!我相信另一个答案会讨论这个问题,这是正确的解决方案。

【讨论】:

  • 你能给我举个例子说明 State monad 将如何提供帮助吗?
  • 使用 Reader monad 查看锤子的答案,这与我向您展示的相同(使用 State monad 没有任何修改 - 所以我也应该想到 Reader)。跨度>
【解决方案3】:
猜你喜欢
  • 2014-03-02
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 2018-11-14
相关资源
最近更新 更多