实现缓存

时间:2009-03-07 00:45:07

标签: caching haskell

我正在尝试实现一个透明缓存,可以在特定对象不可用时加载它,或者返回一个已由(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' []

但我得到了

Occurs check: cannot construct the infinite type:
  t = (ObjType, String -> t)

看起来完全像我想要的东西:)

如何修复函数以便编译?

澄清:

根据要求,签名(findObj返回通过键找到的已知值,或者Nothing,readObj为键创建新的obj):

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

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

4 个答案:

答案 0 :(得分:2)

为什么不只是memoize findObj?

答案 1 :(得分:2)

两个想法(疯狂的猜测?)看起来好像它未能在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 :(得分:2)

Haskell不支持这样的类型:

type t = Int -> t

这是因为编译器尝试展开此类型,以键入检查它。由于类型系统是quit strict,因此在类型检查期间会导致无限循环。现在拥有一个比你能做到的更懒惰的类型系统会更好,但是,目前还没有Haskell。

然而,正如MarkusQ所说,更容易改变loader'函数的作用。我想我会这样写:

type Cache = [(String, ObjType)]

loader' :: Cache -> String -> (ObjType, Cache)

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

答案 3 :(得分:0)

您可能希望查看haskell中的this implementation缓存。