module Data.MemoCombinators.Class 
    ( MemoTable(..)
    , Memoizable(..)
    ) where

import qualified Data.MemoCombinators as Memo
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Word (Word, Word8, Word16, Word32, Word64)
import Data.Ratio (Ratio, numerator, denominator, (%))
import Control.Arrow ((&&&))

-- | The class of types which have complete memo tables.
class MemoTable a where
    table :: Memo.Memo a

instance MemoTable Bool where table :: Memo Bool
table = (Bool -> r) -> Bool -> r
Memo Bool
Memo.bool
instance MemoTable Char where table :: Memo Char
table = (Char -> r) -> Char -> r
Memo Char
Memo.char
instance MemoTable Int  where table :: Memo Int
table = (Int -> r) -> Int -> r
forall a. Integral a => Memo a
Memo Int
Memo.integral
instance MemoTable Int8 where table :: Memo Int8
table = (Int8 -> r) -> Int8 -> r
forall a. Integral a => Memo a
Memo Int8
Memo.integral
instance MemoTable Int16 where table :: Memo Int16
table = (Int16 -> r) -> Int16 -> r
forall a. Integral a => Memo a
Memo Int16
Memo.integral
instance MemoTable Int32 where table :: Memo Int32
table = (Int32 -> r) -> Int32 -> r
forall a. Integral a => Memo a
Memo Int32
Memo.integral
instance MemoTable Int64 where table :: Memo Int64
table = (Int64 -> r) -> Int64 -> r
forall a. Integral a => Memo a
Memo Int64
Memo.integral
instance MemoTable Integer where table :: Memo Integer
table = (Integer -> r) -> Integer -> r
forall a. Integral a => Memo a
Memo Integer
Memo.integral
instance MemoTable Ordering where table :: Memo Ordering
table = (Ordering -> r) -> Ordering -> r
forall a. Enum a => Memo a
Memo Ordering
Memo.enum
instance MemoTable Word where table :: Memo Word
table = (Word -> r) -> Word -> r
forall a. Integral a => Memo a
Memo Word
Memo.integral
instance MemoTable Word8 where table :: Memo Word8
table = (Word8 -> r) -> Word8 -> r
forall a. Integral a => Memo a
Memo Word8
Memo.integral
instance MemoTable Word16 where table :: Memo Word16
table = (Word16 -> r) -> Word16 -> r
forall a. Integral a => Memo a
Memo Word16
Memo.integral
instance MemoTable Word32 where table :: Memo Word32
table = (Word32 -> r) -> Word32 -> r
forall a. Integral a => Memo a
Memo Word32
Memo.integral
instance MemoTable Word64 where table :: Memo Word64
table = (Word64 -> r) -> Word64 -> r
forall a. Integral a => Memo a
Memo Word64
Memo.integral

instance MemoTable () where table :: Memo ()
table = (() -> r) -> () -> r
Memo ()
Memo.unit
instance (MemoTable a, MemoTable b) => MemoTable (a,b) where
    table :: Memo (a, b)
table = (a -> b -> r) -> (a, b) -> r
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((a -> b -> r) -> (a, b) -> r)
-> (((a, b) -> r) -> a -> b -> r) -> ((a, b) -> r) -> (a, b) -> r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b -> r) -> a -> b -> r
forall a. Memoizable a => a -> a
memoize ((a -> b -> r) -> a -> b -> r)
-> (((a, b) -> r) -> a -> b -> r) -> ((a, b) -> r) -> a -> b -> r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, b) -> r) -> a -> b -> r
forall a b c. ((a, b) -> c) -> a -> b -> c
curry
instance (MemoTable a, MemoTable b, MemoTable c) => MemoTable (a,b,c) where
    table :: Memo (a, b, c)
table (a, b, c) -> r
f = \(a
a,b
b,c
c) -> a -> b -> c -> r
m a
a b
b c
c
        where m :: a -> b -> c -> r
m = (a -> b -> c -> r) -> a -> b -> c -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c -> (a, b, c) -> r
f (a
a,b
b,c
c))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d) => MemoTable (a,b,c,d) where
    table :: Memo (a, b, c, d)
table (a, b, c, d) -> r
f = \(a
a,b
b,c
c,d
d) -> a -> b -> c -> d -> r
m a
a b
b c
c d
d
        where m :: a -> b -> c -> d -> r
m = (a -> b -> c -> d -> r) -> a -> b -> c -> d -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d -> (a, b, c, d) -> r
f (a
a,b
b,c
c,d
d))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e) => MemoTable (a,b,c,d,e) where
    table :: Memo (a, b, c, d, e)
table (a, b, c, d, e) -> r
f = \(a
a,b
b,c
c,d
d,e
e) -> a -> b -> c -> d -> e -> r
m a
a b
b c
c d
d e
e
        where m :: a -> b -> c -> d -> e -> r
m = (a -> b -> c -> d -> e -> r) -> a -> b -> c -> d -> e -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e -> (a, b, c, d, e) -> r
f (a
a,b
b,c
c,d
d,e
e))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f) => MemoTable (a,b,c,d,e,f) where
    table :: Memo (a, b, c, d, e, f)
table (a, b, c, d, e, f) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f') -> a -> b -> c -> d -> e -> f -> r
m a
a b
b c
c d
d e
e f
f'
        where m :: a -> b -> c -> d -> e -> f -> r
m = (a -> b -> c -> d -> e -> f -> r)
-> a -> b -> c -> d -> e -> f -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' -> (a, b, c, d, e, f) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f'))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g) => MemoTable (a,b,c,d,e,f,g) where
    table :: Memo (a, b, c, d, e, f, g)
table (a, b, c, d, e, f, g) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g) -> a -> b -> c -> d -> e -> f -> g -> r
m a
a b
b c
c d
d e
e f
f' g
g
        where m :: a -> b -> c -> d -> e -> f -> g -> r
m = (a -> b -> c -> d -> e -> f -> g -> r)
-> a -> b -> c -> d -> e -> f -> g -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g -> (a, b, c, d, e, f, g) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g, MemoTable h) => MemoTable (a,b,c,d,e,f,g,h) where
    table :: Memo (a, b, c, d, e, f, g, h)
table (a, b, c, d, e, f, g, h) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h) -> a -> b -> c -> d -> e -> f -> g -> h -> r
m a
a b
b c
c d
d e
e f
f' g
g h
h
        where m :: a -> b -> c -> d -> e -> f -> g -> h -> r
m = (a -> b -> c -> d -> e -> f -> g -> h -> r)
-> a -> b -> c -> d -> e -> f -> g -> h -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g h
h -> (a, b, c, d, e, f, g, h) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g, MemoTable h, MemoTable i) => MemoTable (a,b,c,d,e,f,g,h,i) where
    table :: Memo (a, b, c, d, e, f, g, h, i)
table (a, b, c, d, e, f, g, h, i) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i) -> a -> b -> c -> d -> e -> f -> g -> h -> i -> r
m a
a b
b c
c d
d e
e f
f' g
g h
h i
i
        where m :: a -> b -> c -> d -> e -> f -> g -> h -> i -> r
m = (a -> b -> c -> d -> e -> f -> g -> h -> i -> r)
-> a -> b -> c -> d -> e -> f -> g -> h -> i -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g h
h i
i -> (a, b, c, d, e, f, g, h, i) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g, MemoTable h, MemoTable i, MemoTable j) => MemoTable (a,b,c,d,e,f,g,h,i,j) where
    table :: Memo (a, b, c, d, e, f, g, h, i, j)
table (a, b, c, d, e, f, g, h, i, j) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j) -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> r
m a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j
        where m :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> r
m = (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> r)
-> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j -> (a, b, c, d, e, f, g, h, i, j) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g, MemoTable h, MemoTable i, MemoTable j, MemoTable k) => MemoTable (a,b,c,d,e,f,g,h,i,j,k) where
    table :: Memo (a, b, c, d, e, f, g, h, i, j, k)
table (a, b, c, d, e, f, g, h, i, j, k) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k) -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> r
m a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k
        where m :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> r
m = (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> r)
-> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k -> (a, b, c, d, e, f, g, h, i, j, k) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g, MemoTable h, MemoTable i, MemoTable j, MemoTable k, MemoTable l) => MemoTable (a,b,c,d,e,f,g,h,i,j,k,l) where
    table :: Memo (a, b, c, d, e, f, g, h, i, j, k, l)
table (a, b, c, d, e, f, g, h, i, j, k, l) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k,l
l) -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> r
m a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k l
l
        where m :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> r
m = (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> r)
-> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k l
l -> (a, b, c, d, e, f, g, h, i, j, k, l) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k,l
l))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g, MemoTable h, MemoTable i, MemoTable j, MemoTable k, MemoTable l, MemoTable m) => MemoTable (a,b,c,d,e,f,g,h,i,j,k,l,m) where
    table :: Memo (a, b, c, d, e, f, g, h, i, j, k, l, m)
table (a, b, c, d, e, f, g, h, i, j, k, l, m) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k,l
l,m
m') -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> r
m a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k l
l m
m'
        where m :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> r
m = (a
 -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> r)
-> a
-> b
-> c
-> d
-> e
-> f
-> g
-> h
-> i
-> j
-> k
-> l
-> m
-> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k l
l m
m' -> (a, b, c, d, e, f, g, h, i, j, k, l, m) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k,l
l,m
m'))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g, MemoTable h, MemoTable i, MemoTable j, MemoTable k, MemoTable l, MemoTable m, MemoTable n) => MemoTable (a,b,c,d,e,f,g,h,i,j,k,l,m,n) where
    table :: Memo (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
table (a, b, c, d, e, f, g, h, i, j, k, l, m, n) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k,l
l,m
m',n
n) -> a
-> b
-> c
-> d
-> e
-> f
-> g
-> h
-> i
-> j
-> k
-> l
-> m
-> n
-> r
m a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k l
l m
m' n
n
        where m :: a
-> b
-> c
-> d
-> e
-> f
-> g
-> h
-> i
-> j
-> k
-> l
-> m
-> n
-> r
m = (a
 -> b
 -> c
 -> d
 -> e
 -> f
 -> g
 -> h
 -> i
 -> j
 -> k
 -> l
 -> m
 -> n
 -> r)
-> a
-> b
-> c
-> d
-> e
-> f
-> g
-> h
-> i
-> j
-> k
-> l
-> m
-> n
-> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k l
l m
m' n
n -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k,l
l,m
m',n
n))
instance (MemoTable a, MemoTable b, MemoTable c, MemoTable d, MemoTable e, MemoTable f, MemoTable g, MemoTable h, MemoTable i, MemoTable j, MemoTable k, MemoTable l, MemoTable m, MemoTable n, MemoTable o) => MemoTable (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) where
    table :: Memo (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
table (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) -> r
f = \(a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k,l
l,m
m',n
n,o
o) -> a
-> b
-> c
-> d
-> e
-> f
-> g
-> h
-> i
-> j
-> k
-> l
-> m
-> n
-> o
-> r
m a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k l
l m
m' n
n o
o
        where m :: a
-> b
-> c
-> d
-> e
-> f
-> g
-> h
-> i
-> j
-> k
-> l
-> m
-> n
-> o
-> r
m = (a
 -> b
 -> c
 -> d
 -> e
 -> f
 -> g
 -> h
 -> i
 -> j
 -> k
 -> l
 -> m
 -> n
 -> o
 -> r)
-> a
-> b
-> c
-> d
-> e
-> f
-> g
-> h
-> i
-> j
-> k
-> l
-> m
-> n
-> o
-> r
forall a. Memoizable a => a -> a
memoize (\a
a b
b c
c d
d e
e f
f' g
g h
h i
i j
j k
k l
l m
m' n
n o
o -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) -> r
f (a
a,b
b,c
c,d
d,e
e,f
f',g
g,h
h,i
i,j
j,k
k,l
l,m
m',n
n,o
o))


instance (MemoTable a) => MemoTable [a] where table :: Memo [a]
table = Memo a -> Memo [a]
forall a. Memo a -> Memo [a]
Memo.list (a -> r) -> a -> r
forall a. MemoTable a => Memo a
Memo a
table
instance (MemoTable a) => MemoTable (Maybe a) where table :: Memo (Maybe a)
table = Memo a -> Memo (Maybe a)
forall a. Memo a -> Memo (Maybe a)
Memo.maybe (a -> r) -> a -> r
forall a. MemoTable a => Memo a
Memo a
table
instance (MemoTable a, MemoTable b) => MemoTable (Either a b) where 
    table :: Memo (Either a b)
table = Memo a -> Memo b -> Memo (Either a b)
forall a b. Memo a -> Memo b -> Memo (Either a b)
Memo.either (a -> r) -> a -> r
forall a. MemoTable a => Memo a
Memo a
table (b -> r) -> b -> r
forall a. MemoTable a => Memo a
Memo b
table
instance (Integral a, MemoTable a) => MemoTable (Ratio a) where
    table :: Memo (Ratio a)
table = ((a, a) -> Ratio a)
-> (Ratio a -> (a, a)) -> Memo (a, a) -> Memo (Ratio a)
forall a b. (a -> b) -> (b -> a) -> Memo a -> Memo b
Memo.wrap ((a -> a -> Ratio a) -> (a, a) -> Ratio a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry a -> a -> Ratio a
forall a. Integral a => a -> a -> Ratio a
(%)) (Ratio a -> a
forall a. Ratio a -> a
numerator (Ratio a -> a) -> (Ratio a -> a) -> Ratio a -> (a, a)
forall b c c'. (b -> c) -> (b -> c') -> b -> (c, c')
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& Ratio a -> a
forall a. Ratio a -> a
denominator) ((a, a) -> r) -> (a, a) -> r
forall a. MemoTable a => Memo a
Memo (a, a)
table


-- | The class of functions which can be completely memoized.
class Memoizable a where
    memoize :: a -> a

instance (MemoTable a) => Memoizable (a -> b) where
    memoize :: (a -> b) -> a -> b
memoize = (a -> b) -> a -> b
forall a. MemoTable a => Memo a
Memo a
table