    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