-------------------------------------------------- |-- Module : Data.MemoCombinators-- Copyright : (c) Luke Palmer 2008-2010-- License : BSD3---- Maintainer : Luke Palmer <lrpalmer@gmail.com>-- Stability : experimental---- This module provides combinators for building memo tables-- over various data types, so that the type of table can-- be customized depending on the application.---- This module is designed to be imported /qualified/, eg.---- > import qualified Data.MemoCombinators as Memo---- Usage is straightforward: apply an object of type @Memo a@-- to a function of type @a -> b@, and get a memoized function-- of type @a -> b@. For example:---- > fib = Memo.integral fib'-- > where-- > fib' 0 = 0-- > fib' 1 = 1-- > fib' x = fib (x-1) + fib (x-2)------------------------------------------------moduleData.MemoCombinators(Memo,wrap,memo2,memo3,memoSecond,memoThird,bool,char,list,boundedList,either,maybe,unit,pair,integral,bits,switch,RangeMemo,arrayRange,unsafeArrayRange,chunks)whereimportPreludehiding(either,maybe)importData.BitsimportqualifiedData.ArrayasArrayimportData.Char(ord,chr)importqualifiedData.IntTrieasIntTrie-- | The type of a memo table for functions of a.typeMemoa=forallr.(a->r)->(a->r)-- | Given a memoizer for a and an isomorphism between a and b, build-- a memoizer for b. wrap::(a->b)->(b->a)->Memoa->Memobwrapijmf=m(f.i).j-- | Memoize a two argument function (just apply the table directly for-- single argument functions).memo2::Memoa->Memob->(a->b->r)->(a->b->r)memo2ab=a.(b.)-- | Memoize a three argument function.memo3::Memoa->Memob->Memoc->(a->b->c->r)->(a->b->c->r)memo3abc=a.(memo2bc.)-- | Memoize the second argument of a function.memoSecond::Memob->(a->b->r)->(a->b->r)memoSecondb=(b.)-- | Memoize the third argument of a function.memoThird::Memoc->(a->b->c->r)->(a->b->c->r)memoThirdc=(memoSecondc.)bool::MemoBoolboolf=cond(fTrue)(fFalse)wherecondtfTrue=tcondtfFalse=flist::Memoa->Memo[a]listmf=table(f[])(m(\x->listm(f.(x:))))wheretablenilcons[]=niltablenilcons(x:xs)=consxxschar::MemoCharchar=wrapchrordintegral-- | Build a table which memoizes all lists of less than the given length.boundedList::Int->Memoa->Memo[a]boundedList0mf=fboundedListnmf=table(f[])(m(\x->boundedList(n-1)m(f.(x:))))wheretablenilcons[]=niltablenilcons(x:xs)=consxxseither::Memoa->Memob->Memo(Eitherab)eithermm'f=table(m(f.Left))(m'(f.Right))wheretablelr(Leftx)=lxtablelr(Rightx)=rxmaybe::Memoa->Memo(Maybea)maybemf=table(fNothing)(m(f.Just))wheretablenjNothing=ntablenj(Justx)=jxunit::Memo()unitf=letm=f()in\()->mpair::Memoa->Memob->Memo(a,b)pairmm'f=uncurry(m(\x->m'(\y->f(x,y))))-- | Memoize an integral type. integral::(Integrala)=>Memoaintegral=wrapfromIntegertoIntegerbits-- | Memoize an ordered type with a bits instance.bits::(Orda,Bitsa)=>Memoabitsf=IntTrie.apply(fmapfIntTrie.identity)-- | @switch p a b@ uses the memo table a whenever p gives-- true and the memo table b whenever p gives false.switch::(a->Bool)->Memoa->Memoa->Memoaswitchpmm'f=table(mf)(m'f)wheretabletfx|px=tx|otherwise=fx-- | The type of builders for ranged tables; takes a lower bound and an upper-- bound, and returns a memo table for that range.typeRangeMemoa=(a,a)->Memoa-- | Build a memo table for a range using a flat array. If items are-- given outside the range, don't memoize.arrayRange::(Array.Ixa)=>RangeMemoaarrayRangerng=switch(Array.inRangerng)(unsafeArrayRangerng)id-- | Build a memo table for a range using a flat array. If items are-- given outside the range, behavior is undefined.unsafeArrayRange::(Array.Ixa)=>RangeMemoaunsafeArrayRangerngf=(Array.listArrayrng(mapf(Array.rangerng))Array.!)-- | Given a list of ranges, (lazily) build a memo table for each one-- and combine them using linear search.chunks::(Array.Ixa)=>RangeMemoa->[(a,a)]->Memoachunksrmemocsf=lookup(cs`zip`map(\rng->rmemorngf)cs)wherelookup[]_=error"Element non in table"lookup((r,c):cs)x|Array.inRangerx=cx|otherwise=lookupcsx