【问题标题】:Implementing a cache实现缓存
【发布时间】:2009-05-10 04:03:02
【问题描述】:

我正在尝试实现一个透明缓存,它可以在特定对象不可用时加载它,或者返回一个由 (name) 索引的现有对象。

我试过运行这个:

loader' objs name = case findObj objs name of
  Nothing →  (new_obj, loader' new_objs)
  Just obj →  (obj, loader' objs)
  where
    new_objs = [(name, new_obj)] ++ objs
    new_obj = readObj name
loader = loader' []

但我得到了一个

发生检查:无法构造无限类型: t = (ObjType, 字符串 -> t)

看起来和我想要的完全一样:)

如何修复函数以便编译?

说明:

根据要求,签名(findObj 要么返回通过密钥找到的已知值,要么返回 Nothing,readObj 为密钥创建一个新 obj):

findObj :: [(String, ObjType)] -> String -> Maybe ObjType
readObj :: String -> ObjType

是的 - 我需要一个缓存,因为键是文件名,我不想在每次需要某个对象时读取+解析文件。

【问题讨论】:

  • 我想我们需要看看 findObj 和 readObj 的定义
  • 你甚至需要函数式语言中的缓存概念吗?我一直认为这是一个命令式优化。
  • 为 findObj、readObj 添加了签名

标签: caching haskell


【解决方案1】:

两个想法(疯狂猜测?)看起来好像它未能在Just obj 子句和/或readObj name 中生成正确的类型签名,尝试这样的事情可能会很有趣:

loader' :: [(String, ObjType)] -> String -> (ObjType, String -> ObjType)
loader' objs name = case findObj objs name of
  Nothing →  (new_obj, loader' new_objs) where
    new_objs = [(name, new_obj)] ++ objs
    new_obj = readObj name
  Just obj →  (obj, loader' objs)
loader = loader' []

我并不是说那会解决它(但我想它可能会);相反,我是说它可能会将问题转化为更有意义的问题,或者以其他方式阐明情况。

编辑:

应用 Tom Lokhorst 对缓存类型命名的建议将我们引向:

type Cache = [(String, ObjType)]
loader' :: Cache -> String -> (ObjType, ????)
loader' objs name = case findObj objs name of
  Nothing →  (new_obj, loader' new_objs) where
    new_objs = [(name, new_obj)] ++ objs
    new_obj = readObj name
  Just obj →  (obj, loader' objs)
loader = loader' []

这让问题很明显。 loader' 的第二个结果的类型是一个接受字符串并产生由 ObjType 组成的对的函数和接受字符串并产生由 ObjType 组成的对的函数和接受字符串并产生对的函数由一个 ObjType 和一个接受字符串的函数组成,并产生一对由 ObjType 和...组成的图片。

如果你这样重写:

type Cache = [(String, ObjType)]
loader' :: Cache -> String -> (ObjType, Cache)
loader' objs name = case findObj objs name of
  Nothing →  (new_obj, new_objs) where
    new_objs = [(name, new_obj)] ++ objs
    new_obj = readObj name
  Just obj →  (obj, objs)

它应该可以编译,但你必须改变你使用它的方式。

【讨论】:

    【解决方案2】:

    为什么不只是memoizefindObj?

    【讨论】:

      【解决方案3】:

      Haskell 不支持这样的类型:

      type t = Int -> t
      

      这是因为编译器试图展开这种类型,对它进行类型检查。由于类型系统是严格退出的,这将导致在类型检查期间出现无限循环。现在有一个更惰性的类型系统会很好,而不是你能做到这一点,但是,目前还没有 Haskell。

      但是,正如 MarkusQ 所说,更改 loader' 函数的功能更容易。我想我会这样写:

      type Cache = [(String, ObjType)]
      
      loader' :: Cache -> String -> (ObjType, Cache)
      

      这是一个获取缓存和搜索字符串的函数,返回答案和(可能更新的)缓存。

      【讨论】:

      • 您的重命名和我的重组相结合非常清楚地表明了问题所在。我修改了我的答案以使用您命名缓存的想法,感谢您并投票支持您的答案。
      【解决方案4】:

      你可能想看看 this implementation haskell 中的缓存。

      【讨论】:

      • 我认为我不需要那么重的东西 - 我需要一个单线程文件加载器......另外 - 我想知道如何解决我的一般问题(一个函数返回自身,部分应用)
      猜你喜欢
      • 2012-05-08
      • 2013-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-09
      • 2018-10-14
      • 2017-11-22
      • 1970-01-01
      相关资源
      最近更新 更多