Метод цепочки вызовов и "булькает" результаты


Мне нужен способ, чтобы создать своего рода стек мест для поиска элемента.

То, что я хочу сделать, это иметь каждый слой искомого элемента, и если он находится на этом уровне, то он должен быть загружен каждый более высокий уровень (последовательно).

Что у меня до сих пор это всего лишь базовая основа, но мне было интересно, если я пропавших без вести некоторые более склонны абстракция вот в плане командной потока. У кого-нибудь есть какие-либо предложения?

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

Чтобы увидеть это в действии, оно должно быть достаточным, чтобы загрузить ГГц и введите:

tester "bar" [inMem,renDisk,onDisk]


198
6
задан 17 декабря 2011 в 02:12 Источник Поделиться
Комментарии
1 ответ

Как насчет сделать inMem и ко "кронштейн" функции? Таким образом:

import Control.Monad.Writer

type M a = Writer String a
type LoadFunc a b = (a -> M b) -> a -> M b

type Query = String
type Result = ()

inMem :: LoadFunc Query Result
inMem _ "hi" = tell "Found in mem. "
inMem f q = f q >> tell "Added to mem. "

renDisk :: LoadFunc Query Result
renDisk _ "foo" = tell "Found rendered. "
renDisk f q = f q >> tell "Added rendered. "

onDisk :: LoadFunc Query Result
onDisk _ "bar" = tell "Found on disk. "
onDisk f q = f q >> tell "Now on disk. "

tester :: [LoadFunc Query Result] -> Query -> M Result
tester = foldr ($) notFound
where notFound q = tell "Not found!"

Запустить через runWriter $ тестер [inMem,renDisk,дисковой] "бар"

Это должно дать вам поток управления вы стремитесь - а также достаточно места для расширения, заменив монады по мере необходимости. Например, вы можете иметь процесс выбрасывать исключение с помощью ошибка вместо монады (которая, вероятно, будет иметь смысл).

4
ответ дан 17 декабря 2011 в 03:12 Источник Поделиться