-- 
-- (c) Susumu Katayama
--
{-# LANGUAGE TemplateHaskell, RankNTypes, CPP, PatternGuards, ImpredicativeTypes #-}
module MagicHaskeller.Instantiate(mkRandTrie, RTrie, -- arbitraries,
                   uncurryDyn, uncurryTy, mkUncurry, typeToOrd, typeToRandomsOrd, typeToRandomsOrdDM, mkCurry, curryDyn, argTypeToRandoms
                  , typeToArb -- exported just for testing Classification.tex
                    , PackedOrd, typeToCompare, compareRealFloat
                  ) where

import MagicHaskeller.CoreLang
import qualified Data.Map as Map
import MagicHaskeller.MyCheck
#ifdef TFRANDOM
import System.Random.TF.Gen
#else
import System.Random
#endif
import MagicHaskeller.Types
import Control.Monad.Search.Combinatorial
import Data.Array((!))
import MagicHaskeller.TyConLib
import MagicHaskeller.DebMT
import Data.List hiding (insert)
import Control.Monad
import qualified Data.IntMap as IntMap

-- import Data.Ratio
import MagicHaskeller.FastRatio

import MagicHaskeller.MyDynamic hiding (dynApp)
-- import Data.Typeable

import MagicHaskeller.ReadDynamic(dynI)

import Data.Memo

import MagicHaskeller.T10
-- import ReadTypeRep(typeToTR)

import Language.Haskell.TH hiding (Type)

import MagicHaskeller.NearEq(NearEq(..))

-- import Debug.Trace
trace _ e = e

dynApp = dynAppErr "in MagicHaskeller.Instantiate"

type Order = Maybe ([Dynamic], PackedOrd)

type ExpResult = ([Dynamic],CoreExpr)
mkUncurry :: TyConLib -> Dynamic
mkUncurry tcl =
                $(dynamic [|tcl|] [| uncurry :: (a->b->c)->((,) a b)->c |])

uncurryDyn :: Dynamic -> Type -> Dynamic -> Dynamic
uncurryDyn unc (_ :-> b@(_:->_)) f = dynAppErr "while uncurrying." unc (uncurryDyn unc b f)
uncurryDyn _   _                 x = x

mkCurry :: TyConLib -> Dynamic
mkCurry tcl =
                $(dynamic [|tcl|] [| curry :: ((,) a b -> c)-> a->b->c |])

curryDyn :: Dynamic -> Type -> Dynamic -> Dynamic
curryDyn cur (_ :-> b@(_:->_)) f = dynAppErr "while currying." cur (curryDyn cur b f)
curryDyn _   _                 x = x

{-
varsInts (TA t u) = TA (varsInts t) (varsInts u)
varsInts (u:->t)  = varsInts u :-> varsInts t
varsInts (TV 
-}
uniqueVars (TA t u) = TA (uniqueVars t) (uniqueVars u)
uniqueVars (u:->t)  = uniqueVars u :-> uniqueVars t
uniqueVars (TV _)   = TV 0
uniqueVars tc       = tc

-- uniqueVars はmemoizeしない場合はやってもしょうがないし,memoizeする場合はsynergeticとそうでないのと両方でやるべきでは?


-- memoizeしない場合
typeToRandomsOrd :: TyConLib -> RTrie -> Type -> Order
typeToRandomsOrd tcl = ttro (\(cmap,maps,_,_,_) -> argTypeToRandoms tcl cmap maps) tcl
typeToRandomsOrdDM :: [Int] -> TyConLib -> RTrie -> Type -> Maybe ([[Dynamic]], PackedOrd)
typeToRandomsOrdDM nrnds tcl = ttro (\(cmap,maps,_,_,_) -> argTypeToRandomss nrnds tcl cmap maps) tcl

{-
-- memoizeする場合
typeToRandomsOrd :: TyConLib -> RTrie -> Type -> Order
typeToRandomsOrd tcl rtrie = ttro (\(_,_,(mtrands,_)) -> lookupMT mtrands) tcl rtrie . uniqueVars
typeToRandomsOrdDM :: TyConLib -> RTrie -> Type -> Maybe ([[Dynamic]], PackedOrd)
typeToRandomsOrdDM tcl rtrie = ttro (\(_,_,(_,mtrands)) -> lookupMT mtrands) tcl rtrie . uniqueVars
-}

ttro :: (RTrie -> Type -> Maybe [a]) -> TyConLib -> RTrie -> Type -> Maybe ([a], PackedOrd)
ttro attr tcl rtrie@(cmap,_,_,_,_) (a1:->rest)
    = let (a,r) = uncurryTy' tcl a1 rest
      in do cmp  <- typeToCompare tcl cmap r
            rnds <- attr rtrie a
            return (rnds, cmp)
ttro attr tcl (cmap, _, _, _, _) t
    = do cmp <- typeToCompare tcl cmap t
         return ([], cmp)



dynToCompare :: TyConLib -> Dynamic -> (Dynamic -> Dynamic -> Ordering)
dynToCompare tcl dyn d0 d1 = fromDyn tcl (dynAppErr "in dynToCompare (1)" (dynAppErr "in dynToCompare (2)" dyn d0) d1) (error "dynToCompare: type mismatch")
--dynToCompare tcl dyn d0 d1 = aLittleSafeFromDyn (readType' tcl "Ordering") (dynApp (dynApp dyn d0) d1)

-- 引数の型が確定しても返り値の型が確定しない場合:たとえばundefinedやerrorとか.このへんをちゃんとtake careしとかないと,むりやりIntに変換することになる....まあいっか?
-- procUndef = Just ([], mkHV (\_ _ -> True))

-- | 'uncurryTy' converts  @a->b->c->d->e->r@ into @((((a,b),c),d),e)->r@
--   Note that @Arbitrary (a,b,c,d,e)@ is not defined in @Test.QuickCheck@.
uncurryTy :: TyConLib -> Type -> Type
uncurryTy tcl (a:->b) = case uncurryTy' tcl a b of (c,r) -> c:->r
uncurryTy _   t       = t
uncurryTy' :: TyConLib -> Type -> Type -> (Type,Type)
uncurryTy' tcl a (b:->r) = uncurryTy' tcl (pair tcl a b) r
uncurryTy' tcl a r       = (a,r)

pair tcl a b = (TA (TA (TC (tuple tcl 2)) a) b)
{-
tupleに対応するやつないし,やっぱTH.Typeに一旦変換した方がよい? あるいは,Types.TypeでTupleを特別視するか.まあ,律速段階ではないので"(,)"みたいな感じでやってもいいけど.
ただ,tclに"(,)"とかが含まれない場合は? 単にdefaultTyConsに入れておけばいいか.ただ,Arbitraryは(,,,)までしか定義されていない.

$(support [t| forall a b c. ((Int,Integer,Char), ([a], Maybe a), (Either a b, (a,b))) |])
みたいに書くとtypeToOrdやtypeToRandomsが生成されてくれると便利.
まあとりあえずは限られた型だけでやってもいいけど.

てゆーか,Ordな型とArbitraryな型は別なので,supportOrd, supportArbの2つを用意しておくか.


てゆーか,Dynamicはどうよ? 同じことか
-}

type PackedOrd = Dynamic -> Dynamic -> Ordering
type Cmp a = a->a->Ordering

#ifdef TFRANDOM
type Generator = TFGen
#else
type Generator = StdGen
#endif
type Maps  = (ArbMap, CoarbMap, Generator, Generator) -- used if we do not memoize
type Tries = (MapType (Maybe [Dynamic]), MapType (Maybe [[Dynamic]])) -- used if we memoize

type RTrie = (CmpMap, Maps, MemoMap,
              Tries,  MapType (Dynamic,Dynamic))

mkRandTrie :: [Int] -> TyConLib -> Generator -> RTrie
mkRandTrie nrnds tcl gen
                   = let arbtup   = mkArbMap tcl
                         coarbtup = mkCoarbMap tcl
                         (g0,g1)  = split gen
                         maps     = (arbtup, coarbtup, g0, g1)
                         cmap     = mkCmpMap tcl
                         mmap     = mkMemoMap tcl
                     in (cmap, maps, mmap,
                            (mkMT tcl (argTypeToRandoms tcl cmap maps), mkMT tcl (argTypeToRandomss nrnds tcl cmap maps)),
                            (mkMT tcl (typeToMemo mmap)))
argTypeToRandoms :: TyConLib -> CmpMap -> Maps -> Type -> Maybe [Dynamic]
argTypeToRandoms  tcl cmap (arbtup, coarbtup, gen, _) a
    = do arb  <- typeToArb arbtup coarbtup a
         return $ arbitrariesByDyn tcl arb gen
argTypeToRandomss :: [Int] -> TyConLib -> CmpMap -> Maps -> Type -> Maybe [[Dynamic]]
argTypeToRandomss nrnds tcl cmap (arbtup, coarbtup, _, gen) a
    = do arb  <- typeToArb arbtup coarbtup a
         let arbssDyn = arbitrariessByDyn nrnds tcl arb gen
         case typeToCompare tcl cmap a of Nothing  -> return arbssDyn
                                          Just cmp -> return $ map (nubByCmp cmp . take 20) arbssDyn
nubByCmp cmp = nubBy (\a b -> cmp a b == EQ)
-- nubByCmpは同じ乱数が入らないようにする働きがある.ただし,Boolなどのように本質的に2種類しかないものに対してnubByCmpして乱数を5つ取ろうとすると無限ループに入ってしまうので,それを避けるためにtake 20を入れている.
-- argTypeToRandomsでもそれをしようとすると結構ややこしいことになるので,そっちではnubByCmpしないことにする.2012/5/29のnewnotes参照.
-- てゆーか,argTypeToRandomssだけで全部やればいいんだけど.

type MapTC a = IntMap.IntMap (IntMap.IntMap a)
type CmpMap = (MapTC Dynamic, SpecialMap, Dynamic)


mkMap :: TyConLib -> [[(String,a)]] -> MapTC a
mkMap tcl@(mapNameTyCon,_) mcts = IntMap.fromAscList $ zip [0..] $ map (IntMap.fromList . map (\ (name, dyn) -> (fromIntegral (mapNameTyCon Map.! name),  dyn))) mcts
mkCmpMap :: TyConLib -> CmpMap
mkCmpMap tcl = (mkMap tcl [mct0, mct1, mct2],
                mkSpecialMap tcl [("Ratio", "Int",     $(dynamic [|tcl|] [| compareRatio :: Ratio Int -> Ratio Int -> Ordering |])),
                                  ("Ratio", "Integer", $(dynamic [|tcl|] [| compareRatio :: Ratio Integer -> Ratio Integer -> Ordering |]))],
                cmpChar)
    where
          cmpChar = $(dynamic [|tcl|] [| compare :: Char -> Char -> Ordering |])
          mct0, mct1, mct2 :: [(String,Dynamic)]
          mct0 = [("Int",     $(dynamic [|tcl|] [| compare      :: Int     -> Int     -> Ordering |])),
                  ("Integer", $(dynamic [|tcl|] [| compare      :: Integer -> Integer -> Ordering |])),
                  ("Char",    cmpChar),
                  ("Bool",    $(dynamic [|tcl|] [| compare      :: Bool    -> Bool    -> Ordering |])),
                  ("Double",  $(dynamic [|tcl|] [| compareRealFloat :: Double  -> Double  -> Ordering |])),
                  ("Float",   $(dynamic [|tcl|] [| compareRealFloat :: Float   -> Float   -> Ordering |])),
                  ("()",      $(dynamic [|tcl|] [| compare      :: ()      -> ()      -> Ordering |])),
                  ("Ordering",$(dynamic [|tcl|] [| compare      :: Ordering-> Ordering-> Ordering |]))]
          mct1 = [("Maybe",   $(dynamic [|tcl|] [| compareMaybe :: (a -> a -> Ordering) -> Maybe a -> Maybe a -> Ordering |])),
                  ("[]",      $(dynamic [|tcl|] [| compareList  :: (a -> a -> Ordering) -> [a]     -> [a]     -> Ordering |]))]
          mct2 = [("Either",  $(dynamic [|tcl|] [| compareEither:: (a -> a -> Ordering) ->
                                                                   (b -> b -> Ordering) -> Either a b -> Either a b -> Ordering |])),
                  ("(,)",     $(dynamic [|tcl|] [| comparePair  :: (a -> a -> Ordering) ->
                                                                   (b -> b -> Ordering) -> (a,b)      -> (a,b)      -> Ordering |]))]
--                  ("Array", unsafeToDyn (readType' tcl "Cmp a -> Cmp b -> Cmp (Array a b)") (\cmp0 cmp1 x y -> compareList (comparePair cmp0 cmp1) (assocs x) (assocs y)))]
--          tto (TA (TA (TA (TC tc) t) u) v) = case (ar ! 3) !! tc of ("(,,)",_) -> packCmp (\ (x0,x1,x2) (y0,y1,y2) -> compareTup  (pair tcl (pair tcl t u) v) ((x0,x1),x2) ((y0,y1),y2))
--                                                                    _          -> Nothing
compareMaybe _   Nothing  Nothing  = EQ
compareMaybe _   Nothing  _        = LT
compareMaybe _   _        Nothing  = GT
compareMaybe cmp (Just x) (Just y) = cmp x y
compareRatio :: Integral i => Ratio i -> Ratio i -> Ordering
compareRatio x y = case (denominator x, denominator y) of (0,0) -> EQ -- Because the comparison is just for removing duplicates efficiently,
                                                          (0,_) -> LT -- notANumber should be a normal element here.
                                                          (_,0) -> GT
                                                          _     -> compare (numerator x * denominator y) (numerator y * denominator x)
compareRealFloat  :: (NearEq a, RealFloat a) => a->a->Ordering
compareRealFloat x y = case (isNaN x, isNaN y) of -- Because the comparison is just for removing duplicates efficiently,
                             (True, True)  -> EQ  -- NaN should be a normal element here.
                             (True, False) -> LT
                             (False,True)  -> GT
                             (False,False) -> if x~=y then EQ else compare x y


compareList _   []     []     = EQ
compareList _   []     _      = LT
compareList _   _      []     = GT
compareList cmp (x:xs) (y:ys) = case cmp x y of EQ -> compareList cmp xs ys
                                                c  -> c
compareEither cmp0 cmp1 (Left x)  (Left y)  = cmp0 x y
compareEither cmp0 cmp1 (Left _)  _         = LT
compareEither cmp0 cmp1 _         (Left _)  = GT
compareEither cmp0 cmp1 (Right x) (Right y) = cmp1 x y
comparePair   cmp0 cmp1 (x0,x1)  (y0,y1) = case cmp0 x0 y0 of EQ -> cmp1 x1 y1
                                                              c  -> c

typeToCompare :: TyConLib -> CmpMap -> Type -> Maybe (Dynamic -> Dynamic -> Ordering)
typeToCompare tcl cmap ty = do cmp <- typeToOrd cmap ty
                               return (dynToCompare tcl cmp)
typeToOrd :: CmpMap -> Type -> Maybe Dynamic
typeToOrd (cmpmap,spmap,cmpchar) ty = tto 0 ty
    where tto 0 (TA (TC tc1) (TC tc2)) | Just dyn <- IntMap.lookup (combineTCs tc1 tc2) spmap = return dyn
          tto k (TA t u) = liftM2 dynApp (tto (k+1) t) (tto 0 u) -- Higher-order kinds break everything.
          tto _ (_:->_)  = Nothing -- error "Functions in containers are not allowed." -- note that ty is (part of) the return type, so this means higher-order datatype is returned.
          tto 0 (TV _)   = Just cmpchar -- same as the Char case
          tto _ (TV _)   = Nothing -- これについては一般的なやりかたはなさそう.
          tto k (TC tc)  = do guard (tc >= 0)
                              imap <- IntMap.lookup k cmpmap
                              IntMap.lookup (fromIntegral tc) imap
          tto _ _        = Nothing
type ArbMap   = (MapTC Dynamic, SpecialMap, Dynamic, Dynamic)
type CoarbMap = (MapTC Dynamic, SpecialMap, Dynamic, Dynamic)

mkArbMap :: TyConLib -> ArbMap
mkArbMap tcl@(mapNameTyCon,_) = (mkMap tcl [mct0, mct1, mct2, mct3],
                                 mkSpecialMap tcl [("Ratio", "Int",     $(dynamic [|tcl|] [| arbitraryRatio   :: Gen (Ratio Int) |])),
                                                   ("Ratio", "Integer", $(dynamic [|tcl|] [| arbitraryRatio   :: Gen (Ratio Integer) |]))],
                                arbChar, -- same as the Char case
                                $(dynamic [|tcl|] [| arbitraryFun :: (a -> Gen b -> Gen b) -> Gen b -> Gen (a->b) |])
                                )

    where
          arbChar = $(dynamic [|tcl|] [| arbitraryChar :: Gen Char |])
          mct0, mct1, mct2, mct3 :: [(String,Dynamic)]
          mct0 = [("Int",     $(dynamic [|tcl|] [| arbitraryInt     :: Gen Int |])),
                  ("Char",    arbChar),
                  ("Integer", $(dynamic [|tcl|] [| arbitraryInteger :: Gen Integer |])),
                  ("Bool",    $(dynamic [|tcl|] [| arbitraryBool    :: Gen Bool    |])),
                  ("Double",  $(dynamic [|tcl|] [| arbitraryDouble  :: Gen Double  |])),
                  ("Float",   $(dynamic [|tcl|] [| arbitraryFloat   :: Gen Float   |])),
                  ("()",      $(dynamic [|tcl|] [| arbitraryUnit    :: Gen ()      |])),
                  ("Ordering",$(dynamic [|tcl|] [| arbitraryOrdering:: Gen Ordering|]))]
          mct1 = [("Maybe",   $(dynamic [|tcl|] [| arbitraryMaybe   :: Gen a -> Gen (Maybe a) |])),
                  ("[]",      $(dynamic [|tcl|] [| arbitraryList    :: Gen a -> Gen [a]       |]))]
          mct2 = [("Either",  $(dynamic [|tcl|] [| arbitraryEither  :: Gen a -> Gen b -> Gen (Either a b) |])),
                  ("(,)",     $(dynamic [|tcl|] [| arbitraryPair    :: Gen a -> Gen b -> Gen (a, b)       |]))]
          mct3 = [("(,,)",    $(dynamic [|tcl|] [| arbitraryTriplet :: Gen a -> Gen b -> Gen c -> Gen (a,b,c) |]))]

-- ArbMap specialized for Ratio Int, etc. 
-- This is necessary because we cannot have something like arbitraryRatio :: Gen a -> Gen (Ratio a) (without type constraint),
-- in order to avoid zero-denominator cases.
type SpecialMap = IntMap.IntMap Dynamic
mkSpecialMap :: TyConLib -> [(String,String,Dynamic)] -> IntMap.IntMap Dynamic
mkSpecialMap tcl@(mapNameTyCon,_) = IntMap.fromList . map (\ (name1, name2, dyn) -> (combineTCs (mapNameTyCon Map.! name1) (mapNameTyCon Map.! name2),  dyn)) 

{- こっちにすべき ---------------------------------------
-- This signature silently makes sure that TyCon == Int8. This should cause an error when TyCon /= Int8.
combineTCs :: Int8 -> Int8 -> Int
combineTCs tc1 tc2 = fromIntegral tc1 * 256 + fromIntegral tc2
-}
-- debug目的でこっちにしている。---------------------------------
combineTCs :: TyCon -> TyCon -> Int
combineTCs tc1 tc2 = fromIntegral tc1 * 256 + fromIntegral tc2


typeToArb :: ArbMap -> CoarbMap -> Type -> Maybe Dynamic
typeToArb arbtup@(arbmap, spmap, arbchar, arbfun) coarbtup@(coarbmap, _, coarbchar, coarbfun) ty = tta 0 ty
    where
          tta 0 ty@(t :-> u) = do coarb <- typeToCoarb arbtup coarbtup t
                                  arb   <- tta 0 u
                                  return (-- trace ("t = "++show t++" and u = "++show u ++ " and coarb = "++show coarb) $
                                          dynApp (dynApp arbfun coarb) arb)
          tta 0 (TV _)  = Just arbchar -- same as the Char case
          tta _ (TV _)  = Nothing -- これについては一般的なやりかたはなさそう.
          tta k (TC tc)
              = do guard (tc >= 0)
                   imap <- IntMap.lookup k arbmap
                   IntMap.lookup (fromIntegral tc) imap
          tta 0 (TA (TC tc1) (TC tc2)) | Just dyn <- IntMap.lookup (combineTCs tc1 tc2) spmap = return dyn
          tta k (TA t0 t1) = do arb0 <- tta (k+1) t0
                                arb1 <- tta 0     t1
                                return (-- trace ("t0 = "++show t0++" and t1 = "++show t1) $
                                        dynApp arb0 arb1)
          tta _ _ = Nothing
mkCoarbMap :: TyConLib -> CoarbMap
mkCoarbMap tcl@(mapNameTyCon,_) = (mkMap tcl [mct0, mct1, mct2, mct3],
                                   mkSpecialMap tcl [("Ratio", "Int",     $(dynamic [|tcl|] [| coarbitraryRatio   :: Ratio Int -> Gen x -> Gen x |])),
                                                     ("Ratio", "Integer", $(dynamic [|tcl|] [| coarbitraryRatio   :: Ratio Integer -> Gen x -> Gen x |]))],
                                   coarbChar, -- same as the Char case
                                   $(dynamic [|tcl|] [| coarbitraryFun :: Gen a -> (b -> Gen x -> Gen x) -> (a->b) -> Gen x -> Gen x |])
                                  )
    where coarbChar = $(dynamic [|tcl|] [| coarbitraryChar :: Char -> Gen x -> Gen x |])
          mct0, mct1, mct2, mct3 :: [(String,Dynamic)]
          mct0 = [("Int",      $(dynamic [|tcl|] [| coarbitraryInt     :: Int     -> Gen x -> Gen x |])),
                  ("Char",     coarbChar),
                  ("Integer",  $(dynamic [|tcl|] [| coarbitraryInteger  :: Integer  -> Gen x -> Gen x |])),
                  ("Bool",     $(dynamic [|tcl|] [| coarbitraryBool     :: Bool     -> Gen x -> Gen x |])),
                  ("Double",   $(dynamic [|tcl|] [| coarbitraryDouble   :: Double   -> Gen x -> Gen x |])),
                  ("Float",    $(dynamic [|tcl|] [| coarbitraryFloat    :: Float    -> Gen x -> Gen x |])),
                  ("()",       $(dynamic [|tcl|] [| coarbitraryUnit     :: ()       -> Gen x -> Gen x |])),
                  ("Ordering", $(dynamic [|tcl|] [| coarbitraryOrdering :: Ordering -> Gen x -> Gen x |]))]
          mct1 = [("[]",     $(dynamic [|tcl|] [| coarbitraryList   :: (a -> Gen x -> Gen x) -> [a]     -> Gen x -> Gen x |])),
                  ("Maybe",  $(dynamic [|tcl|] [| coarbitraryMaybe  :: (a -> Gen x -> Gen x) -> Maybe a -> Gen x -> Gen x |]))]
          mct2 = [("Either", $(dynamic [|tcl|] [| coarbitraryEither :: (a -> Gen x -> Gen x) ->
                                                                       (b -> Gen x -> Gen x) -> Either a b -> Gen x -> Gen x |])),
                  ("(,)",    $(dynamic [|tcl|] [| coarbitraryPair   :: (a -> Gen x -> Gen x) ->
                                                                       (b -> Gen x -> Gen x) -> (a, b) -> Gen x -> Gen x |]))]
          mct3 = [("(,,)",   $(dynamic [|tcl|] [| coarbitraryTriplet:: (a -> Gen x -> Gen x) ->
                                                                       (b -> Gen x -> Gen x) ->
                                                                       (c -> Gen x -> Gen x) -> (a,b,c) -> Gen x -> Gen x |]))]
typeToCoarb :: ArbMap -> CoarbMap -> Type -> Maybe Dynamic
typeToCoarb arbtup@(arbmap,_,arbchar,arbfun) coarbtup@(coarbmap,spmap,coarbchar,coarbfun) ty = ttc 0 ty
    where -- ttc :: Type -> Maybe (Coarb Dynamic)
          ttc 0 ty@(t :-> u) = do arb <- typeToArb arbtup coarbtup t
                                  coarb <- ttc 0 u
                                  return (dynApp (dynApp coarbfun arb) coarb)
          ttc 0 (TV _)  = Just coarbchar -- same as the Char case
          ttc _ (TV _)  = Nothing
          ttc k (TC tc)
              = do guard (tc >= 0)
                   imap <- IntMap.lookup k coarbmap
                   IntMap.lookup (fromIntegral tc) imap
          ttc 0 (TA (TC tc1) (TC tc2)) | Just dyn <- IntMap.lookup (combineTCs tc1 tc2) spmap = return dyn
          ttc k (TA t0 t1) = do arb0 <- ttc (k+1) t0
                                arb1 <- ttc 0     t1
                                return (-- trace ("arb0 = "++show arb0++"arb1 = "++show arb1) $
                                        dynApp arb0 arb1)
          ttc _ _ = Nothing -- めんどくさいので取り合えず.



type MemoMap = (IntMap.IntMap (IntMap.IntMap (Dynamic,Dynamic)), (Dynamic,Dynamic))
mkMemoMap :: TyConLib -> MemoMap
mkMemoMap tcl@(mapNameTyCon,_) = (mkMap tcl [mct0, mct1, mct2, mct3],
                                  memoAppChar)
    where memoAppChar = ( $(dynamic [|tcl|] [| memoChar :: (Char->a) -> MapChar a |]), 
                          $(dynamic [|tcl|] [| appChar  :: MapChar a -> (Char->a) |]) )
          mct0, mct1, mct2, mct3 :: [(String,(Dynamic,Dynamic))]
          mct0 = [("Int",     ($(dynamic  [|tcl|] [| memoIx3      :: (Int->a) -> MapIx Int a |]),
                               $(dynamic  [|tcl|] [| appIx       :: MapIx Int a -> (Int->a) |]))),
                  ("Char",    memoAppChar),
                  ("Integer", ($(dynamic  [|tcl|] [| memoInteger  :: (Integer->a) -> MapInteger a |]),
                               $(dynamic  [|tcl|] [| appInteger   :: MapInteger a -> (Integer->a) |]))),
                  ("Bool",    ($(dynamic  [|tcl|] [| memoBool     :: (Bool->a) -> MapBool a |]),
                               $(dynamic  [|tcl|] [| appBool      :: MapBool a -> (Bool->a) |]))),
                  ("Ordering",($(dynamic  [|tcl|] [| memoOrdering :: (Ordering->a) -> MapOrdering a |]),
                               $(dynamic  [|tcl|] [| appOrdering  :: MapOrdering a -> (Ordering->a) |]))),
                  ("()",      ($(dynamic  [|tcl|] [| memoUnit     :: (()->a) -> MapUnit a |]),
                               $(dynamic  [|tcl|] [| appUnit      :: MapUnit a -> (()->a) |]))),
                  ("Double",  ($(dynamic  [|tcl|] [| memoReal     :: (Double->a) -> MapReal a |]),
                               $(dynamic  [|tcl|] [| appReal      :: MapReal a -> (Double->a) |]))),
                  ("Float",   ($(dynamic  [|tcl|] [| memoReal     :: (Float->a) -> MapReal a |]),
                               $(dynamic  [|tcl|] [| appReal      :: MapReal a -> (Float->a) |])))]
          mct1 = [("[]",      ($(dynamicH [|tcl|] 'memoList      [t| forall m b a. (forall c. (b->c) -> m c) -> ([b] -> a) -> MapList m b a |]), -- use an undefined type, because forall is not supported. (But then does this work? I don't think so....) でも,単にforallを取ってinfinite typeを許せばOKって気もする.どうよ?
                               $(dynamicH [|tcl|] 'appList1     [t| forall m b a. (forall c. m c -> (b->c)) -> MapList m b a -> ([b]->a) |]))),
                  ("Maybe",   ($(dynamic  [|tcl|] [| memoMaybe    :: ((b->a)->m a) -> (Maybe b->a) -> MapMaybe m a |]),
                               $(dynamic  [|tcl|] [| appMaybe     :: (m a->(b->a)) -> MapMaybe m a -> (Maybe b -> a) |])))]
          mct2 = [("Either",  ($(dynamic  [|tcl|] [| memoEither   :: ((b->a) -> m a) ->
                                                                     ((d->a) -> n a) ->
                                                                        (Either b d -> a) -> MapEither m n a |]),
                               $(dynamic  [|tcl|] [| appEither    :: (m a -> (b->a)) ->
                                                                     (n a -> (d->a)) ->
                                                                        MapEither m n a -> (Either b d -> a) |]))),
                  ("(,)",     ($(dynamicH [|tcl|] 'memoPair      [t| forall m n b d a.
                                                                     (forall e. (b->e) -> m e) ->
                                                                     (forall f. (d->f) -> n f) ->
                                                                        ((b,d) -> a) -> MapPair m n a |]),
                               $(dynamicH [|tcl|] 'appPair       [t| forall m n b d a.
                                                                     (forall e. m e -> (b->e)) ->
                                                                     (forall f. n f -> (d->f)) ->
                                                                        MapPair m n a -> ((b,d) -> a) |])))]
          mct3 = [("(,,)",    ($(dynamicH [|tcl|] 'memoTriplet   [t| forall l m n b c d a.
                                                                     (forall f. (b->f) -> l f) ->
                                                                     (forall e. (c->e) -> m e) ->
                                                                     (forall e. (d->e) -> n e) ->
                                                                        ((b,c,d) -> a) -> MapTriplet l m n a |]),
                               $(dynamicH [|tcl|] 'appTriplet    [t| forall l m n b c d a.
                                                                     (forall e. l e -> (b->e)) ->
                                                                     (forall e. m e -> (c->e)) ->
                                                                     (forall e. n e -> (d->e)) ->
                                                                        MapTriplet l m n a -> ((b,c,d) -> a) |])))]
memoLength = 10
typeToMemo :: MemoMap -> Type -> (Dynamic,Dynamic)
typeToMemo memotup@(memomap,memochar) ty = case ttc 0 ty of Nothing -> (dynI,dynI) -- メモできない場合.テストするときは取り合えず全部(dynI,dynI)にしてもいいかも.
                                                            Just t  -> t
    where ttc 0 (t:->u) = Nothing
          ttc 0 (TV _)  = Just memochar
          ttc _ (TV _)  = Nothing
          ttc k (TC tc) | tc < 0    = Nothing
                        | otherwise = do imap <- IntMap.lookup k memomap
                                         IntMap.lookup (fromIntegral tc) imap
          ttc k (TA t0 t1) = do (m0,a0) <- ttc (k+1) t0
                                (m1,a1) <- ttc 0     t1
                                return (dynApp m0 m1, dynApp a0 a1)
          ttc _ _          = Nothing
-- Test.QuickCheck.GenはRandom.StdGen限定で,それ以外のRandomGen g => gではダメみたい.
-- Test.QuickCheck.generateの定義がちょっと変だと思う.usableだとは思うけど.

type Arb a = Generator -> [a]

arbitrariesByDyn :: TyConLib -> Dynamic -> Arb Dynamic
arbitrariesByDyn tcl arb = arbsByDyn tcl arb 0
arbsByDyn :: TyConLib -> Dynamic -> Int -> Generator -> [Dynamic]
arbsByDyn tcl arbDyn depth stdgen = zipWith (genAppDyn tcl arbDyn) [depth..] (gens stdgen)

genAppDyn :: TyConLib -> Dynamic -> Int -> Generator -> Dynamic
genAppDyn tcl arbDyn size stdgen = dynApp $(dynamic [|tcl|] [| (\(Gen f) -> f size stdgen) :: Gen a -> a |] ) arbDyn

{- 実際もう使われていないし.間違えてこっちを編集しちゃうので,隠す.
arbitrariesBy :: Gen a -> Arb a
arbitrariesBy arb = arbsBy arb 0
arbsBy :: Gen a -> Int -> StdGen -> [a]
arbsBy (Gen f) n stdgen = case split stdgen of (g0,g1) -> f n g0 : arbsBy arb (n+1) g1

arbitraries :: Arbitrary a => Arb a
arbitraries = arbitrariesBy arbitrary
-}



-- nrndsは実はsizeを決めるためにしか使われていない.得られるのはStream (Bag Dynamic)ではなくStream (Stream Dynamic)
arbitrariessByDyn :: [Int] -> TyConLib -> Dynamic -> Generator -> [[Dynamic]]
arbitrariessByDyn nrnds tcl arb gen = abd nrnds tcl arb 0 gen
-- abd _ _ arb depth gen = zipWith (arbsByDyn arb) [depth..] (gens gen) -- 乱数サイズを小さい値から増やしていく場合
abd nrnds tcl arb depth gen = zipWith (arbsByDyn' nrnds tcl arb) [depth..] (gens gen) -- 乱数サイズを一定にする場合
arbsByDyn' nrnds tcl arbDyn depth stdgen = map (genAppDyn tcl arbDyn size) (gens stdgen)
    where size = max depth (nrnds !! depth)
#ifdef TFRANDOM
gens gen = case map (splitn gen 8) [0..255] of g0:gs -> gs ++ gens g0
#else
gens gen = case split gen of (g0,g1) -> g0 : gens g1
#endif