packages feed

MagicHaskeller-0.8.6: MagicHaskeller/Analytical/Synthesize.hs

-- 
-- (C) Susumu Katayama
--
{-# LANGUAGE CPP #-}
module MagicHaskeller.Analytical.Synthesize where

import Data.List(transpose)
-- import Control.Monad.Search.RecompDL -- a version using DList, but did not actually improve the efficiency.
import Control.Monad -- hiding (guard)
import Control.Monad.State -- hiding (guard)
import qualified Data.IntMap as IntMap

import Language.Haskell.TH

import Control.Monad.Search.Combinatorial
import MagicHaskeller.CoreLang hiding (C)
import qualified MagicHaskeller.Types as Types
import MagicHaskeller.TyConLib
import MagicHaskeller.PriorSubsts hiding (unify)

import MagicHaskeller.Analytical.Syntax
import MagicHaskeller.Analytical.Parser
import MagicHaskeller.Analytical.UniT
import MagicHaskeller.Analytical.FMExpr

-- | function specification by examples.
data Fun = BKF {maxNumBVs :: Int, arity :: Int, iopairs :: [IOPair], fmexpr :: FMExpr [IOPair]} -- ^ the function is really a background knowledge (and thus there is no need for loop check)     
         | Rec {maxNumBVs :: Int, arity :: Int, iopairs :: [IOPair], fmexpr :: FMExpr [IOPair], toBeSought :: TBS} -- ^ it is actually a recursive call.
mkBKFun          iops@(iop:_) = BKF {maxNumBVs = maximum $ map numUniIDs iops, arity = length $ inputs iop, iopairs = iops, fmexpr = iopsToFME iops}
mkRecFun ari tbs iops@(iop:_) = Rec {maxNumBVs = maximum $ map numUniIDs iops, arity = ari, iopairs = iops, fmexpr = iopsToVisFME tbs iops, toBeSought = tbs} -- arity = filter id tbs, but it is usually know beforehand
setIOPairs iops recfun@Rec{toBeSought=tbs} = recfun{iopairs = iops, fmexpr = iopsToVisFME tbs iops}
type BK  = [Types.Typed Fun]      -- ^ background knowledge.

applyFun s fun = fun{iopairs = applyIOPs s (iopairs fun)}


analyticSynth :: Search m => TyConLib -> VarLib -> [Dec] -> [Dec] -> m CoreExpr
analyticSynth tcl vl target bkdec = fst $ analyticSynthAndInfType tcl vl target bkdec
analyticSynthAndInfType :: Search m => TyConLib -> VarLib -> [Dec] -> [Dec] -> (m CoreExpr, Types.Type)
analyticSynthAndInfType tcl vl target bkdec
    = case unPS (liftM2 (,) (parseTypedIOPairss tcl xvl target) (parseTypedIOPairss tcl xvl bkdec)) Types.emptySubst 0 of
        Nothing -> error "Type error occurred while reading the IO pairs."
        Just (([],_),_,_) ->error "TypedIOPairs.analyticSynth*: No I/O pairs are defined as the target."
        Just (([(targetFunName, iops@(iop:_) Types.:::ty)],bktups),_,mx) ->
               let (bknames, bktiopss) = unzip bktups
                   (bkiopss, bktypes)  = unzipTyped bktiopss
                   target = mkRecFun aritar tbs iops
                   tbs = replicate aritar True                   
                   aritar = length $ inputs iop
                   bk = reverse $ zipWith (Types.:::) (map mkBKFun $ bkiopss) bktypes
               in (fmap (\e -> napply (length bktups) FunLambda $ napply aritar Lambda (Fix e aritar [aritar-1, aritar-2..0])) $   --  $ Fix e $ map X [arity-1, arity-2 .. 0]) $     -- ËÜÅö¤Ï¤³¤Î·ë²Ì¤Î¤½¤ì¤¾¤ì¤Ë bknames¤òŬÍѤ·¤¿¤¤¤Î¤À¤¬¡¤bknames¤ÊHValue¤¬¤Ê¤¤¤Î¤Ç.... ¤Æ¤æ¡¼¤«¡¤Exp¤Ê¤éºî¤ì¤ë¡¥CoreExpr¤â¡¤BK¤¬Á´ÉôVarLib¤Ë¤Ï¤¤¤Ã¤Æ¤¤¤ì¤Ðºî¤ì¤ë¡¥
                   analSynthm {- analSynthNoUniT ¤³¤Ã¤Á¤À¤È¤Á¤ç¤Ã¤È¤¤¤¤²Ã¸º¤Ç¤Á¤ç¤Ã¤È®¤¤ -} bk (target Types.:::ty)
                  ,ty)
        _ -> error "TypedIOPairs.analyticSynth*: More than one I/O pairs are defined as the target."
    where xvl = mkXVarLib vl


analSynth, analSynthm :: Search m => BK -> Types.Typed Fun -> m CoreExpr
analSynth bk tfun@(fun Types.::: _) | any hasExistential $ map output $ iopairs fun = fmap fst $ runStateT (analSynthUTm bk tfun) emptySt
                                    | otherwise                                  = analSynthm bk tfun
analSynthm bk tfun
    = others `mplus` delay bkRelated
  where newbk = tfun : bk
        bkRelated = headSpine analSynth introBKm newbk tfun 
        others    = headSpine analSynthm (introConstr +++ introVarm +++ ndelayIntro 2 introCase) newbk tfun
headSpine rec intro bk tfun 
  = do (hd, subfuns, mbpivot) <- intro bk tfun
       subexps <- mapM (\subfun -> let arisub = arity $ Types.typee subfun in fmap (\e -> Fix e arisub (mkArgs mbpivot arisub)) $ rec bk subfun)  subfuns
       return (hd subexps)
#ifdef DEBUG
headSpine_debug rec trs intro bk tfun 
  = do (hd, subfuns, mbpivot) <- intro bk tfun
       subexps <- zipWithM (\tr subfun -> let arisub = arity $ Types.typee subfun in fmap (\e -> Fix e arisub (mkArgs mbpivot arisub)) $ rec tr bk subfun) trs subfuns
       return (hd subexps)
#endif

analSynthUTm :: Search m => BK -> Types.Typed Fun -> UniT m CoreExpr
-- analSynthm ([], _, _) = mzero -- If there is no example, nothing can be done. (But is this line necessary?)
analSynthUTm bk (fun Types.::: ty)
    = do 
         s <- gets subst
         let aptfun = applyFun s fun Types.::: ty
             newbk  = aptfun : bk
         headSpine analSynthUTm introAny newbk aptfun

mkArgs Nothing arisub = [arisub-1,arisub-2..0]
mkArgs (Just pivot) arisub = take pivot [arisub,arisub-1..] ++ [arisub-pivot-1,arisub-pivot-2..0]

#ifdef DEBUG
analyticSynthNoUniT_debug :: Search m => Tree (Introducer m) ->  TyConLib -> VarLib -> [Dec] -> [Dec] -> m CoreExpr
analyticSynthNoUniT_debug tree tcl vl target bkdec
    = case unPS (liftM2 (,) (parseTypedIOPairss tcl xvl target) (parseTypedIOPairss tcl xvl bkdec)) Types.emptySubst 0 of
        Nothing -> error "Type error occurred while reading the IO pairs."
        Just (([],_),_,_) ->error "TypedIOPairs.analyticSynth*: No I/O pairs are defined as the target."
        Just (([(targetFunName, iops@(iop:_) Types.:::ty)],bktups),_,mx) ->
               let (bknames, bktiopss) = unzip bktups
                   (bkiopss, bktypes)  = unzipTyped bktiopss
                   target = mkRecFun aritar tbs iops
                   tbs = replicate aritar True                   
                   aritar = length $ inputs iop
                   bk = reverse $ zipWith (Types.:::) (map mkBKFun $ bkiopss) bktypes
               in (fmap (\e -> napply (length bktups) FunLambda $ napply aritar Lambda (Fix e aritar [aritar-1, aritar-2..0])) $   --  $ Fix e $ map X [arity-1, arity-2 .. 0]) $     -- ËÜÅö¤Ï¤³¤Î·ë²Ì¤Î¤½¤ì¤¾¤ì¤Ë bknames¤òŬÍѤ·¤¿¤¤¤Î¤À¤¬¡¤bknames¤ÊHValue¤¬¤Ê¤¤¤Î¤Ç.... ¤Æ¤æ¡¼¤«¡¤Exp¤Ê¤éºî¤ì¤ë¡¥CoreExpr¤â¡¤BK¤¬Á´ÉôVarLib¤Ë¤Ï¤¤¤Ã¤Æ¤¤¤ì¤Ðºî¤ì¤ë¡¥
                   analSynthNoUniT_debug tree bk (target Types.:::ty)
                  )
        _ -> error "TypedIOPairs.analyticSynth*: More than one I/O pairs are defined as the target."
    where xvl = mkXVarLib vl
-- analSynthNoUniT is inaccurate, but should work in most cases. This can be used in place of analSynthm
analSynthNoUniT bk tfun
  = headSpine analSynthNoUniT (introConstr +++ introVarm +++ ndelayIntro 2 introCase +++ ndelayIntro 1 introBKm) (tfun:bk) tfun
analSynthNoUniT_debug (Br intro trs) bk tfun
  = headSpine_debug analSynthNoUniT_debug trs intro (tfun:bk) tfun


data Tree x = Br x [Tree x] deriving Show
tryall, tryVar :: Search m => Tree (IntroUniT m)
tryall = Br introAny (repeat tryall)
tryVar = Br introVarUTm []
tryVarm :: (Functor m, MonadPlus m) => Tree (Introducer m)
tryVarm = Br introVarm []

analyticSynth_debug :: Search m => Tree (IntroUniT m) -> TyConLib -> VarLib -> [Dec] -> [Dec] -> m CoreExpr
analyticSynth_debug tree tcl vl target bkdec
    = do ((tgt,bktups),_,mx) <-
             unPS (liftM2 (,) (parseTypedIOPairss tcl xvl target) (parseTypedIOPairss tcl xvl bkdec)) Types.emptySubst 0
         case tgt of
           [] -> error "analyticSynth: No I/O pairs are defined as the target."
           [(targetFunName, iops@(iop:_) Types.:::ty)] ->
               let (bknames, bktiopss) = unzip bktups
                   (bkiopss, bktypes)  = unzipTyped bktiopss
                   target = mkRecFun aritar tbs iops
                   tbs = replicate aritar True
                   aritar = length $ inputs iop
                   bk = reverse $ zipWith (Types.:::) (map mkBKFun $ bkiopss) bktypes
               in fmap (\(e,_st) -> napply (length bktups) FunLambda $ napply aritar Lambda (Fix e aritar [aritar-1, aritar-2..0])) $   --  $ Fix e $ map X [arity-1, arity-2 .. 0]) $     -- ËÜÅö¤Ï¤³¤Î·ë²Ì¤Î¤½¤ì¤¾¤ì¤Ë bknames¤òŬÍѤ·¤¿¤¤¤Î¤À¤¬¡¤bknames¤ÊHValue¤¬¤Ê¤¤¤Î¤Ç.... ¤Æ¤æ¡¼¤«¡¤Exp¤Ê¤éºî¤ì¤ë¡¥CoreExpr¤â¡¤BK¤¬Á´ÉôVarLib¤Ë¤Ï¤¤¤Ã¤Æ¤¤¤ì¤Ðºî¤ì¤ë¡¥
                        runStateT (analSynthUT_debug tree bk (target Types.::: ty)) emptySt -- ONLY DIFFER HERE.
           _ -> error "analyticSynth: More than one I/O pairs are defined as the target."
    where xvl = mkXVarLib vl

-- | 'analSynthUT_debug' can be used to try only the given introducer at each selection point. @analSynthUT = analSynthUT_debug tryall@
analSynthUT_debug :: Search m => Tree (IntroUniT m) -> BK -> Types.Typed Fun -> UniT m CoreExpr
analSynthUT_debug (Br intro iss) bk (fun Types.::: ty)
    = do
         s <- gets subst
         let aptfun = applyFun s fun Types.::: ty
             newbk   = aptfun : bk
         (hd, subfuns, mbpivot) <- intro newbk aptfun
         subexps <- zipWithM (\is subfun -> let arisub = arity $ Types.typee subfun in fmap (\e -> Fix e arisub (mkArgs mbpivot arisub)) $ analSynthUT_debug is newbk subfun) iss subfuns
         return (hd subexps)
#endif

type Introducer m = BK -> Types.Typed Fun -> m ([CoreExpr] -> CoreExpr, [Types.Typed Fun], Maybe Int)
type IntroUniT m = Introducer (UniT m)
-- NB: We should not use @StateT Env@ where @Env=(BK,TBS)@ because the Env affects only subexpressions.

il +++ ir = \bk iops -> il bk iops `mplus` ir bk iops
ndelayIntro n intro = \e a -> ndelay n $ intro e a

introAny :: Search m => IntroUniT m
introAny     =          introConstr +++ {- +/ -} (
                        introVarUTm +++
                        ndelayIntro 1 introBKUTm +++
                        ndelayIntro 2 introCase )

(+/) :: MonadPlus m => IntroUniT [] -> IntroUniT m -> IntroUniT m
m +/ n = \bk iops ->
         do st <- get
       	    case runStateT (m bk iops) st of [] -> n bk iops
                                             ts -> StateT $ \_ -> msum $ map return ts
liftList :: MonadPlus m => StateT s [] a -> StateT s m a
liftList = mapStateT (msum . map return)

introVarm, introConstr, introCase :: (Functor m, MonadPlus m) => Introducer m -- introConstr¤Ç¤Ï¡¤¼ÂºÝ¤Ë¤ÏCoreExpr¤ÏConstr¤Ç¤è¤¤¡¥
introBKm :: (Search m) => Introducer m -- introConstr¤Ç¤Ï¡¤¼ÂºÝ¤Ë¤ÏCoreExpr¤ÏConstr¤Ç¤è¤¤¡¥
introVarUTm, introBKUTm :: MonadPlus m => IntroUniT m
-- introVarUTm¤Ï°ìÏ¢¤ÎIgor´Ø·¸¤ÎÏÀʸ¤Ë¤Ï¤Ê¤¤¤â¤Î¤Î¡¤introBK¤¬Í­¸ú¤ËƯ¤¯¤Ë¤ÏɬÍס¥¤³¤ì¤¬¤Ê¤¤¤È¡¤f¤òºî¤ë¤Î¤ËBK¤È¤·¤Æf¤ò»È¤Ã¤Æ¤â¡¤introBK¤À¤±¤Ç½ª¤ï¤Ã¤Æ¤¯¤ì¤º¡¤À¸À®¤µ¤ì¤Ê¤¤¡¥
{- introBK¤Î¤¢¤È¤ÎintroVarUTm¤òintroBK¤Ë´Þ¤á¤è¤¦¤È¤·¤Æ¡¤¤ä¤Ã¤Ñ»ß¤á¤¿¡¥
introVarUTm (iops,_,_,True) = mzero
introVarUTm (iops,_,_,False)  = msum $ map (\(ix,_) -> return (const (X ix), [])) $ filter (\(_,inp) -> inp == map output iops) $ zip [0..] $ transpose $ map inputs iops
-}
-- introVarUTm (iops,_,_,_)  = msum $ map (\(ix,_) -> return (const (X ix), [])) $ filter (\(_,inp) -> inp == map output iops) $ zip [0..] $ transpose $ map inputs iops
introVarUTm b f = liftList $ introVar (zipWithM_ appUnifyUT) b f
-- introVarm b f  = introVar (zipWithM_ unify) b f  *************************************** ¤³¤ì¤Ï¥Ç¥Ð¥Ã¥°»þ¤ËÍ­ÍѤʤ³¤È¤â¡¥
introVarm   = introVar (\a b -> guard $ a==b)

introVar :: MonadPlus m => ([Expr] -> [Expr] -> m ()) -> Introducer m
introVar cmp _ (fun Types.::: ty)
               = do let (argtys, retty) = Types.splitArgs ty
                        iops = iopairs fun
                        arifun = arity fun
                    let trins = transpose $ map inputs iops
--                    (ix,inps Types.::: argty) <- msum $ map return $ zip [0..] trins
                    (ix,argty,inps) <- msum [ return t | t@(_,aty,_) <- zip3 [0..] argtys $ visibles (toBeSought fun) trins, aty == retty ]

-- The following four lines should be equivalent to
                    cmp (map output iops) inps
-- but use of Maybe and simpler substitutions should be good for efficiency.
{-
                    st0 <- get
                    case runStateT (zipWithM_ appUnifyUT (map output iops) inps) st0{subst=[]} of
                              Just ((),st) -> put (st{subst= subst st `plusSubst` subst st0})
	  	     	      Nothing      -> mzero
-}
                    return (const (X ix), [], Nothing)

introConstr bk (fun Types.::: ty)
    = let argtys = Types.getArgs ty 
          iops   = iopairs fun
      in
      case [ output iop | iop <- iops ] of
        outs@(C _ (cid Types.::: cty) flds : rest)
            | all (`sConstrIs` cid) rest -> return (foldl (:$) (Primitive cid),
                                                    zipWith (\iops retty -> setIOPairs iops fun Types.::: Types.popArgs argtys retty)
                                                            (transpose [ divideIOP iop | iop <- iops ])
                                                            (case Types.revSplitArgs cty of (_,fieldtys,_) -> fieldtys),
                                                    Nothing)
        _                        -> mzero
divideIOP (IOP bvs ins out) = map (IOP bvs ins) $ fields out -- The actual number of buondVars may reduce, but not updating the field would not hurt.

shareConstr (C _ (cid Types.::: _) _ : iops) = all (`sConstrIs` cid) iops 
shareConstr _                = False
-- type¤¬°ã¤¦¤ÈƱ¤¸cid¤ò°Û¤Ê¤ëconstructor¤Ç»È¤¤ÆÀ¤ë¾ì¹ç¡¤type¤´¤ÈÈæ³Ó¤¹¤ëɬÍפ¬¤¢¤ë¤¬¡¤¸½ºß¤Ï¤½¤¦¤Ç¤Ï¤Ê¤¤¤Î¤Ç¡¥
C _ (c Types.::: _) _ `sConstrIs` cid = cid==c
_                     `sConstrIs` cid = False


select []     []      = []
select (b:bs) (p:ps) | b         = (p, False:bs) : rest
                     | otherwise = rest
            where rest = [ (result, b:newbs) | (result,newbs) <- select bs ps ]

introCase bk (fun Types.::: ty) = msum $ reverse $ zipWith introCase' [0..] $ select (toBeSought fun) trins
    where trins = transpose $ map inputs iops
          (argtys,retty) = Types.splitArgs ty
          iops   = iopairs fun
          arifun = arity fun
          introCase' :: MonadPlus m =>
                         Int              -- ^ the pivot position
                         -> ([Expr],TBS)  -- ^ (the pivot expression for each I/O pair, the next TBS)
                         -> m ([CoreExpr] -> CoreExpr, [Types.Typed Fun], Maybe Int)
          introCase' pos (pivots, tbs) -- includes variable cases. Overlapping patterns are not supported yet.
              = case mapM maybeCtor pivots of 
                  Nothing -> mzero
                  Just ctors
                      -> let
                             pipairs = zip pivots iops :: [(Expr,IOPair)]
                             ts      = IntMap.toList $ IntMap.fromListWith (\(t,xs) (_,ys) -> (t,xs++ys)) $
                                           zipWith (\(c Types.::: ct) x -> (c,(ct,[x]))) ctors pipairs
                                               :: [(Constr, (Types.Type, [(Expr,IOPair)]))]
                  -- Array.accum can also be used instead of IntMap because we can tell the range from that of VarLib.
                             hd ces = Case (X pos)
                                            (zipWith (\(constr, (_, (pivot,_):_)) ce -> (constr, length (fields pivot), ce))
                                                     ts
                                                     ces)
                             iopss  = [ Rec { maxNumBVs  = maxNumBVs fun, 
                                              arity      = arifun-1+lenflds,
                                              iopairs    = iops,
                                              fmexpr     = iopsToVisFME newtbs iops,
                                              toBeSought = newtbs
                                            }
                                          Types.::: Types.popArgs (dropNth pos argtys) (Types.popArgs (Types.getArgs cty) retty)
                                      | (_c, (cty, nextpipairs@((C _ _ flds', _):_))) <- ts,
                                        let lenflds = length flds'
                                            iops    = [ IOP bvs (reverse flds ++ is) o | (C _ _c flds, IOP bvs is o) <- nextpipairs ]
                                            newtbs  = replicate lenflds True ++ tbs
                                      ]
                         in return (hd, iopss, Just (arifun-pos-1))

dropNth pos bs = case splitAt pos bs of (tk,_:dr) -> tk ++ dr



introBKm   bk tfun = fromMx $ toMx $ introBK subtractIOPairsFromIOPairsBKm subtractIOPairsFromIOPairsm bk tfun
introBKUTm bk tfun = liftList $ introBK (const subtractIOPairsFromIOPairsBKUTm) (const subtractIOPairsFromIOPairsUTm) bk tfun
introBK subBK sub bk (fun Types.:::ty) = do          
                              let (argtys, retty) = Types.splitArgs ty
                              (ix, bkfun Types.::: bkty) <- msum $ map return $ tail $ zip [0..] bk
                                              -- The tail function here is used to avoid generating expressions like
                                              -- fix (\fa x1 ... xn -> fa ...).
                                              -- Such expressions would be excluded by the loop checker even without the tail function, 
                                              -- but we exclude them beforehand for efficiency reasons.
                              let (bkargtys, bkretty) = Types.splitArgs bkty
                              substy <- Types.match bkretty retty
                              iopss <- case bkfun of BKF{maxNumBVs=addendum} -> subBK (-addendum) (iopairs fun) bkfun
                                                     Rec{maxNumBVs=addendum} -> sub (-addendum) initTS (iopairs fun) bkfun
                              return (foldl (:$) (FunX ix),
                                      [ setIOPairs iops fun Types.::: tys 
                                      | iops Types.::: tys <- reverse $ 
                                                              zipWith (\x retty -> x Types.::: Types.popArgs argtys retty)
                                                                      (transpose iopss)
                                                                      (map (Types.apply substy) bkargtys) ],
                                      Nothing)



subtractIOPairsFromIOPairsBKUTm :: MonadPlus m => [IOPair] -> Fun -> UniT m [[IOPair]]
{-
subtractIOPairsFromIOPairsBK funs bks = foldr (liftM2 (:)) (return []) $ map (flip subtractIOPairs bks) funs
-}
subtractIOPairsFromIOPairsBKUTm []         bkf = return []
subtractIOPairsFromIOPairsBKUTm (fun:funs) bkf = do 
                                                 iops <- subtractIOPairsBKUTm fun bkf
                                                 iopss <- subtractIOPairsFromIOPairsBKUTm funs bkf -- iops¤Ï¡¤subfunction¤¬Ê£¿ô¤¢¤Ã¤Æ¡¤¤½¤ì¤ésubfunctions¤Î¤½¤ì¤¾¤ì¤Ë´Ø¤·¤ÆIOPair1¸Ä¤º¤Ä¤Ë²á¤®¤Ê¤¤¡¥
                                                 return (iops:iopss)
-- Applying substitutions to funs is not currently necessary (because funs does not include existential variables), but that will be useful in future versions which fill gaps of input examples.

{-
subtractIOPairs :: IOPair -> [IOPair] -> [[IOPair]] -- Æâ¦¥ê¥¹¥È¤Î´ð¿ô¤Ïfun¤Îarity, ³°Â¦¤Ïbk¤ÎIO pair¤Î¤¦¤Ámatch¤¹¤ë¤Î¤Ï¤¤¤¯¤Ä¤¢¤ë¤«
                                                    -- ¤Æ¤æ¡¼¤«¡¤Æâ¦¤Ïbk¤Îarity¤Ç¤Ï¡©
subtractIOPairs fun bkpairs = [ iops | bk <- bkpairs, iops <- subtractIOPair fun bk ]
-}
subtractIOPairsBKUTm :: MonadPlus m => IOPair -> Fun -> UniT m [IOPair] -- Æâ¦¥ê¥¹¥È¤Î´ð¿ô¤Ïfun¤Îarity, ³°Â¦¤Ïbk¤ÎIO pair¤Î¤¦¤Ámatch¤¹¤ë¤Î¤Ï¤¤¤¯¤Ä¤¢¤ë¤«
                                                    -- ¤Æ¤æ¡¼¤«¡¤Æâ¦¤Ïbk¤Îarity¤Ç¤Ï¡©
subtractIOPairsBKUTm tgt bkf = do 
                               s <- gets subst
                               let aptgt = applyIOP  s tgt
                                   apbkf = applyIOPs s $ iopairs bkf
                               bkiop <- msum $ map return apbkf
                               subtractIOPairUTm aptgt bkiop
subtractIOPairsFromIOPairsUTm :: MonadPlus m => TermStat -> [IOPair] -> Fun -> UniT m [[IOPair]]
{-
subtractIOPairsFromIOPairs funs bks = foldr (\fun rest -> do iops <- subtractIOPairs fun bks
                                                             iopss <- rest
                                                             return (iops:iopss)) (return []) funs
-}
subtractIOPairsFromIOPairsUTm ts []         bkf = return []
subtractIOPairsFromIOPairsUTm ts (fun:funs) bkf = do
                                (iops,newts) <- subtractIOPairsUTm ts fun bkf
                                iopss        <- subtractIOPairsFromIOPairsUTm newts funs bkf -- iops¤Ï¡¤subfunction¤¬Ê£¿ô¤¢¤Ã¤Æ¡¤¤½¤ì¤ésubfunctions¤Î¤½¤ì¤¾¤ì¤Ë´Ø¤·¤ÆIOPair1¸Ä¤º¤Ä¤Ë²á¤®¤Ê¤¤¡¥
                                return (iops:iopss)
subtractIOPairsUTm :: MonadPlus m => TermStat -> IOPair -> Fun -> UniT m ([IOPair], TermStat) -- Æâ¦¥ê¥¹¥È¤Î´ð¿ô¤Ïfun¤Îarity, ³°Â¦¤Ïbk¤ÎIO pair¤Î¤¦¤Ámatch¤¹¤ë¤Î¤Ï¤¤¤¯¤Ä¤¢¤ë¤«
                                                    -- ¤Æ¤æ¡¼¤«¡¤Æâ¦¤Ïbk¤Îarity¤Ç¤Ï¡©
subtractIOPairsUTm ts tgt bkf = do
                                s <- gets subst
                                let aptgt = applyIOP s tgt
                                    bktbs = toBeSought bkf
                                    -- apbkf = applyIOPs s bkf
                                    apvistgt = reverse $ visibles (reverse bktbs) $ reverse $ inputs aptgt
                                bkiop <- msum $ map return $ iopairs bkf
                                let visbki = visibles bktbs $ inputs bkiop
                                guard $ evalTS $ updateTS visbki apvistgt ts  -- apply¤¹¤ë¤Þ¤¨¤Îbkf¤ÇÅ굡Ū¤Ëfilter¤·¤Æ¤ß¤¿¤±¤É¡¤¤¤¤Þ¤¤¤Á¡¥
                                let apvisbki = map (apply s) visbki
                                iops <- subtractIOPairUTm aptgt bkiop{inputs=apvisbki, output=apply s $ output bkiop}
                                let newts = updateTS apvisbki apvistgt ts -- This makes sure that the generated program does not go into a loop.
                                guard $ evalTS newts
--                                guard $ lessExprss (reverse bkis) (reverse apis)
                                return (iops, newts)

-- Î㤨¤Ð¡¤join [x,y] [z,w] = [x,y,z,w]¤«¤ébk [a,b] [c,d] = [a,c,b,d]¤ò°ú¤¯¤³¤È¤ò¹Í¤¨¤ë¡¥
-- join [x,y] [z,w] = bk (f [x,y] [z,w]) (g [x,y] [z,w])¤Ë¤ª¤¤¤Æf [x,y] [z,w] = [x,z], g [x,y] [z,w] = [y,w]¤Ê¤Î¤Ç¡¤
-- subtractIOPair IOP{inputs=[[x,y],[z,w]],output=[x,y,z,w]} IOP{inputs=[[a,b],[c,d]],output=[a,c,b,d]} = [IOP{inputs=[[x,y],[z,w]],output=[x,z]}, IOP{inputs=[[x,y],[z,w]],output=[y,w]}]
-- ¤È¤¤¤¦¤³¤È¤Ë¤Ê¤ë¡¥
subtractIOPairUTm :: MonadPlus m => IOPair -> IOPair -> UniT m [IOPair]
subtractIOPairUTm fun bkiop
                      = do frbkiop <- freshIOP bkiop
                           unifyUT (output frbkiop) (output fun)
                           s <- gets subst
                           return [ fun{output=apply s o} | o <- inputs frbkiop ] -- This @apply@ is necessary here because introBKm will soon forget the substitution.

subtractIOPairsFromIOPairsm :: Int -- maxNumBVs¤Ç¥²¥Ã¥È¤Ç¤­¤ëÃÍ¡¥
                               -> TermStat -> [IOPair] -> Fun -> [] [[IOPair]]
subtractIOPairsFromIOPairsm addendum ts tgt bkf = subtractIOPairsFromIOPairsmFME addendum ts tgt bkf addendum
subtractIOPairsFromIOPairsmFME :: Int -> TermStat -> [IOPair] -> Fun -> Int -> [] [[IOPair]]
{-
subtractIOPairsFromIOPairsBK funs bks = foldr (liftM2 (:)) (return []) $ map (flip subtractIOPairs bks) funs
-}
subtractIOPairsFromIOPairsmFME addendum ts []         bkf offset = return []
subtractIOPairsFromIOPairsmFME addendum ts (fun:funs) bkf offset = do 
                                                 (iops,newts) <- subtractIOPairsmFME ts fun bkf offset
                                                 iopss <- subtractIOPairsFromIOPairsmFME addendum newts funs bkf (offset+addendum) -- iops¤Ï¡¤subfunction¤¬Ê£¿ô¤¢¤Ã¤Æ¡¤¤½¤ì¤ésubfunctions¤Î¤½¤ì¤¾¤ì¤Ë´Ø¤·¤ÆIOPair1¸Ä¤º¤Ä¤Ë²á¤®¤Ê¤¤¡¥
                                                 return (iops:iopss)
-- Applying substitutions to funs is not currently necessary (because funs does not include existential variables), but that will be useful in future versions which fill gaps of input examples.

subtractIOPairsmFME :: TermStat -> IOPair -> Fun -> Int -> [([IOPair], TermStat)] -- ÊÖ¤êÃͤÎ[IOPair]¤Ï³Æ°ú¿ô¤ËÂбþ
subtractIOPairsmFME ts tgtiop bkf offset = do 
                                let vistgt = reverse $ visibles (reverse $ toBeSought bkf) $ reverse $ inputs tgtiop
                                visbkis <- unifyingIOPairs (output tgtiop) (fmexpr bkf) offset
                                let iops = [ tgtiop{output=o} | o <- visbkis ]
                                let newts = updateTS visbkis vistgt ts -- This makes sure that the generated program does not go into a loop.
                                guard $ evalTS newts
--                                guard $ lessExprss (reverse bkis) (reverse apis)
                                return (iops, newts)
                                
                                
subtractIOPairsFromIOPairsBKm :: Int -- maxNumBVs¤Ç¥²¥Ã¥È¤Ç¤­¤ëÃÍ¡¥
                                 -> [IOPair] -> Fun -> [] [[IOPair]]
subtractIOPairsFromIOPairsBKm addendum tgt bkf = subtractIOPairsFromIOPairsBKmFME addendum tgt (iopsToFME $ iopairs bkf) addendum
subtractIOPairsFromIOPairsBKmFME :: Int -> [IOPair] -> FMExpr [IOPair] -> Int -> [] [[IOPair]]
{-
subtractIOPairsFromIOPairsBK funs bks = foldr (liftM2 (:)) (return []) $ map (flip subtractIOPairs bks) funs
-}
subtractIOPairsFromIOPairsBKmFME addendum []         bkf offset = return []
subtractIOPairsFromIOPairsBKmFME addendum (fun:funs) bkf offset = do 
                                                 iops <- subtractIOPairsBKmFME fun bkf offset
                                                 iopss <- subtractIOPairsFromIOPairsBKmFME addendum funs bkf (offset+addendum) -- iops¤Ï¡¤subfunction¤¬Ê£¿ô¤¢¤Ã¤Æ¡¤¤½¤ì¤ésubfunctions¤Î¤½¤ì¤¾¤ì¤Ë´Ø¤·¤ÆIOPair1¸Ä¤º¤Ä¤Ë²á¤®¤Ê¤¤¡¥
                                                 return (iops:iopss)
-- Applying substitutions to funs is not currently necessary (because funs does not include existential variables), but that will be useful in future versions which fill gaps of input examples.
                              
                                
                                
subtractIOPairsBKmFME :: IOPair -> FMExpr [IOPair] -> Int -> [] [IOPair] -- ÊÖ¤êÃͤÎ[IOPair]¤Ï³Æ°ú¿ô¤ËÂбþ
subtractIOPairsBKmFME tgtiop bkfme offset = do 
                                visbkis <- unifyingIOPairs (output tgtiop) bkfme offset
                                return [ tgtiop{output=o} | o <- visbkis ]


unifyingIOPairs :: Expr -> FMExpr [IOPair] -> Int -> [] [Expr]
unifyingIOPairs e fme 0      = [ inputs iop | (iops, _) <- unifyFME e fme, iop <- iops ]
unifyingIOPairs e fme offset = [ map (mapE (offset+) . apfresh s) $ inputs iop | (iops, s) <- unifyFME e fme, iop <- iops ]