I’m trying to implement a transparent cache that can load a specific object when it’s not available, or return an already existing object indexed by (name).
I’ve tried running this:
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' []
but I’m getting a
Occurs check: cannot construct the infinite type: t = (ObjType, String -> t)
which looks exactly like something I want 🙂
How can I fix the function so that it compiles?
Clarifications:
As requested, signatures (findObj either returns a known value found via a key, or Nothing, readObj creates a new obj for a key):
findObj :: [(String, ObjType)] -> String -> Maybe ObjType readObj :: String -> ObjType
And yes – I need a cache, because the keys are filenames and I don’t want to read+parse the file each time some object is needed.
Two thoughts (wild guesses?) it looks as if it is failing to produce the right type signature in the
Just objclause and/or fromreadObj name, and it might be interesting to try something like this:I’m not saying that that will fix it (but I suppose that it might); rather, I’m saying that it may transform the problem into one that makes more sense, or otherwise shed light on the situation.
Edit:
Applying Tom Lokhorst’s suggestion of naming the cache type leads us to this:
which makes it obvious what the problem is. The type of the second result of loader’ is a function that takes a string an produces a pair consisting of an ObjType and a function that takes a string an produces a pair consisting of an ObjType and a function that takes a string an produces a pair consisting of an ObjType and a function that takes a string an produces a pair consisting of an ObjType and … you get the picture.
If you rewrite it like this:
it should compile but you’ll have to change how you use it.