I need a way to build up a sort of stack of places to search for an item.
What I would like to do is to have each layer searched for an item, and if it is found at that level, then it should be loaded by each higher level (successively).
What I have so far is just a basic framework, but I was wondering if I was missing some more apt abstraction here in terms of command flow. Does anyone have any suggestions?
type Result = String
type Query = String
type Search = Query -> Maybe Result
type Load = Result -> Maybe Result
data LoadFunc = LoadFunc {
search :: Search,
load :: Load }
data RunFunc = RunFunc { runner :: [RunFunc] -> Maybe Result }
mkRunFunc :: Query -> LoadFunc -> RunFunc
mkRunFunc q lf = RunFunc r
where r (x:xs) =
case search lf q of
Nothing -> runner x xs >>= load lf
a -> a
r [] = search lf q
inMem :: LoadFunc
inMem = LoadFunc { search = search, load = load }
where search q = if q == "hi" then return $ "Found in mem." else Nothing
load = addToLog "Loaded to mem."
renDisk :: LoadFunc
renDisk = LoadFunc { search = search, load = load }
where search q = if q == "foo" then return $ "Found rendered." else Nothing
load = addToLog "Added rendered."
onDisk :: LoadFunc
onDisk = LoadFunc { search = search, load = load }
where search q = if q == "bar" then return $ "Found on disk." else Nothing
load = addToLog "Now on disk."
addToLog :: Result -> Result -> Maybe Result
addToLog next str = return $ str ++ (' ':next)
tester :: [LoadFunc] -> Query -> Maybe Result
tester caches q = runner first rem
where caches' = mk `fmap` caches
first = head caches'
rem = tail caches'
mk = mkRunFunc q
To see this in action, it should be sufficient to load up ghci and enter:
tester "bar" [inMem,renDisk,onDisk]