packages feed

data-memocombinators 0.1 → 0.2

raw patch · 2 files changed

+117/−15 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.MemoCombinators: bits :: (Ord a, Bits a) => Memo a
+ Data.MemoCombinators: boundedList :: Int -> Memo a -> Memo [a]
+ Data.MemoCombinators: either :: Memo a -> Memo b -> Memo (Either a b)
+ Data.MemoCombinators: integral :: (Integral a) => Memo a
+ Data.MemoCombinators: list :: Memo a -> Memo [a]
+ Data.MemoCombinators: maybe :: Memo a -> Memo (Maybe a)
+ Data.MemoCombinators: pair :: Memo a -> Memo b -> Memo (a, b)
+ Data.MemoCombinators: switch :: (a -> Bool) -> Memo a -> Memo a -> Memo a
+ Data.MemoCombinators: unit :: Memo ()
+ Data.MemoCombinators: unsafeArrayRange :: (Ix a) => RangeMemo a
+ Data.MemoCombinators: unsignedBits :: (Bits a) => Memo a
- Data.MemoCombinators: type RangeMemo a = a -> a -> Memo a
+ Data.MemoCombinators: type RangeMemo a = (a, a) -> Memo a

Files

Data/MemoCombinators.hs view
@@ -6,26 +6,41 @@ -- -- Maintainer : Luke Palmer <lrpalmer@gmail.com> -- Stability  : experimental--- Portability : presumably portable -- -- 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) ------------------------------------------------  module Data.MemoCombinators      ( Memo     , memo2, memo3, memoSecond, memoThird-    , bool+    , bool, list, boundedList, either, maybe, unit, pair+    , switch, integral, bits, unsignedBits     , RangeMemo-    , arrayRange-    , chunks+    , arrayRange, unsafeArrayRange, chunks     ) where +import Prelude hiding (either, maybe)+import Data.Bits import qualified Data.Array as Array --- | The type of a memo table.+-- | The type of a memo table for functions of a. type Memo a = forall r. (a -> r) -> (a -> r)  -- | Memoize a two argument function (just apply the table directly for@@ -45,27 +60,114 @@ memoThird :: Memo c -> (a -> b -> c -> r) -> (a -> b -> c -> r) memoThird c = (memoSecond c .) --- | A memo table for bools. bool :: Memo Bool bool f = cond (f True) (f False)     where     cond t f True  = t     cond t f False = f +list :: Memo a -> Memo [a]+list m f = table (f []) (m (\x -> list m (f . (x:))))+    where+    table nil cons [] = nil+    table nil cons (x:xs) = cons x xs++-- | Build a table which memoizes all lists of less than the given length.+boundedList :: Int -> Memo a -> Memo [a]+boundedList 0 m f = f+boundedList n m f = table (f []) (m (\x -> boundedList (n-1) m (f . (x:))))+    where+    table nil cons [] = nil+    table nil cons (x:xs) = cons x xs++either :: Memo a -> Memo b -> Memo (Either a b)+either m m' f = table (m (f . Left)) (m' (f . Right))+    where+    table l r (Left x) = l x+    table l r (Right x) = r x++maybe :: Memo a -> Memo (Maybe a)+maybe m f = table (f Nothing) (m (f . Just))+    where+    table n j Nothing = n+    table n j (Just x) = j x++unit :: Memo ()+unit f = let m = f () in \() -> m++pair :: Memo a -> Memo b -> Memo (a,b)+pair m m' f = uncurry (m (\x -> m' (\y -> f (x,y))))++-- | @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) -> Memo a -> Memo a -> Memo a+switch p m m' f = table (m f) (m' f)+    where+    table t f x | p x       = t x+                | otherwise = f x++-- | Memoize an integral type.+integral :: (Integral a) => Memo a+integral = switch (>= 0) unsignedIntegral (\f -> unsignedIntegral (f . negate) . negate)++integralBits :: (Integral a) => a -> [Bool]+integralBits 0 = []+integralBits x = let (q,r) = quotRem x 2 in toBool r : integralBits q+    where+    toBool 0 = False+    toBool 1 = True++integralFromBits :: (Integral a) => [Bool] -> a+integralFromBits [] = 0+integralFromBits (x:xs) = unbit x + 2*integralFromBits xs+    where unbit True = 1 ; unbit False = 0++unsignedIntegral :: (Integral a) => Memo a+unsignedIntegral f = list bool (f . integralFromBits) . integralBits+++-- | Memoize an ordered type with a bits instance.  Good for most integral+-- types.+bits :: forall a. (Ord a, Bits a) => Memo a+bits | isSigned (undefined :: a) +            = switch (>= 0) unsignedBits (\f -> unsignedBits (f . negate) . negate)+     | otherwise = unsignedBits+       +-- | Memoize an unsigned type with a bits instance.  Good for nonnegative+-- integral types.  Warning: if a negative @Integer@ is given to an+-- @unsignedBits@-ized function, it will loop forever.+unsignedBits :: (Bits a) => Memo a+unsignedBits f = list bool (f . unsignedFromBits) . unsignedToBits++unsignedToBits :: (Bits a) => a -> [Bool]+unsignedToBits 0 = []+unsignedToBits x = testBit x 0 : unsignedToBits (shiftR x 1)++unsignedFromBits :: (Bits a) => [Bool] -> a+unsignedFromBits [] = 0+unsignedFromBits (x:xs)  = unbit x .|. shiftL (unsignedFromBits xs) 1+    where unbit True = 1 ; unbit False = 0++ -- | The type of builders for ranged tables; takes a lower bound and an upper--- bound, and returns a memo table for that range.  The table's behavior is--- undefined for values outside that range.-type RangeMemo a = a -> a -> Memo a+-- bound, and returns a memo table for that range.+type RangeMemo a = (a,a) -> Memo a --- | Build a memo table for a range using a flat array.+-- | Build a memo table for a range using a flat array.  If items are+-- given outside the range, don't memoize. arrayRange :: (Array.Ix a) => RangeMemo a-arrayRange lo hi f = (Array.listArray rng (map f (Array.range rng)) Array.!)-    where rng = (lo,hi)+arrayRange rng = switch (Array.inRange rng) (unsafeArrayRange rng) id +-- | Build a memo table for a range using a flat array.  If items are+-- given outside the range, behavior is undefined.+unsafeArrayRange :: (Array.Ix a) => RangeMemo a+unsafeArrayRange rng f = (Array.listArray rng (map f (Array.range rng)) Array.!)++ -- | Given a list of ranges, (lazily) build a memo table for each one -- and combine them using linear search. chunks :: (Array.Ix a) => RangeMemo a -> [(a,a)] -> Memo a-chunks rmemo cs f = lookup (cs `zip` map (\(a,b) -> rmemo a b f) cs)+chunks rmemo cs f = lookup (cs `zip` map (\rng -> rmemo rng f) cs)     where     lookup [] _ = error "Element non in table"     lookup ((r,c):cs) x | Array.inRange r x = c x
data-memocombinators.cabal view
@@ -1,7 +1,7 @@ Name: data-memocombinators Description:     Combinators for building memo tables.-Version: 0.1+Version: 0.2 Stability: experimental Synopsis: Combinators for building memo tables. License: BSD3@@ -11,4 +11,4 @@ Build-Type: Simple Build-Depends: base, array Exposed-Modules: Data.MemoCombinators-Extensions: Rank2Types+Extensions: Rank2Types, ScopedTypeVariables