[If indirectCall can derive closed helper functions, use only those.
tobias@goedderz.info**20150303093405
 Ignore-this: a3884663790b31b398603381e529f62f
 
 Added a function bestMatchings that can generally compute exactly the same IO
 examples as allMatchings, but prunes all which result in open helper functions
 (which compute the arguments).
 
 This behaviour is scheduled to be refined later.
 
 If bestMatchings' result is not empty it will be used instead of allMatchings'
 result. This results in a shorter running time and, on our current test cases,
 in exactly the same results.
] hunk ./src/Igor2/Data/Hypotheses.hs 40
-import Igor2.Data.Rules hiding (sameSymAt)
+import Igor2.Data.Rules hiding (sameSymAt, isOpen, isClosed)
hunk ./src/Igor2/Data/Hypotheses.hs 272
+
hunk ./src/Igor2/Data/IOData.hs 13
-import Igor2.Data.Rules hiding (mapRuleRhsM, mapRuleLhsM, mapRuleM)
-import qualified Igor2.Data.Rules as Rules (mapRuleM)
+import Igor2.Data.Rules hiding (mapRuleRhsM, mapRuleLhsM, mapRuleM, isOpen, isClosed)
+import qualified Igor2.Data.Rules as Rules (mapRuleM, isOpen, isClosed)
hunk ./src/Igor2/Data/IOData.hs 188
-    rule <- lggRules rules
+    rule <- lift $ lggRules rules
hunk ./src/Igor2/Data/IOData.hs 207
-    alterEvidence n rs $
---    alterRhss     n rs $
---    alterLhss     n rs $ 
-    iod
-    
+    alterEvidence n rs iod
+
hunk ./src/Igor2/Data/IOData.hs 212
-    iod{evidence = M.insert n rs evi} 
-       
+    iod { evidence = M.insert n rs evi }
+
hunk ./src/Igor2/Data/IOData.hs 247
-
- -- | A rule is open if it is not closed
hunk ./src/Igor2/Data/IOData.hs 248
-isOpen = not.isClosed
-
--- | A rule is closed if it does not have any open positions
-isClosed = null . openPositions . crul
+isOpen = Rules.isOpen . crul
hunk ./src/Igor2/Data/IOData.hs 250
+isClosed :: CovrRule -> Bool
+isClosed = Rules.isClosed . crul
hunk ./src/Igor2/Data/IOData.hs 274
+
hunk ./src/Igor2/Data/Rules.hs 7
-    hasHO, freeVars, hasFreeVars, openPositions, lggRules, matchLhss, 
+    hasHO, freeVars, hasFreeVars, openPositions, lggRules, matchLhss,
hunk ./src/Igor2/Data/Rules.hs 9
-    Rules, mkRules, rules, subrule, mkCallAt,     
+    Rules, mkRules, rules, subrule, mkCallAt,
hunk ./src/Igor2/Data/Rules.hs 11
+    isOpen, isClosed,
hunk ./src/Igor2/Data/Rules.hs 13
-    insertM, deleteM, replaceM,    
+    insertM, deleteM, replaceM,
hunk ./src/Igor2/Data/Rules.hs 127
-    	             
+
+ -- | A rule is open if it is not closed
+isOpen :: Rule -> Bool
+isOpen = not . isClosed
+
+-- | A rule is closed if it does not have any open positions
+isClosed :: Rule -> Bool
+isClosed = null . openPositions
+
hunk ./src/Igor2/Data/Rules.hs 207
-lggRules :: [Rule] -> LM Rule
+lggRules :: (Monad m, MonadError e m, Error e) => [Rule] -> C m Rule
hunk ./src/Igor2/Data/Rules.hs 221
-        r <-  lift $  lggL (tlhss++[rhss])
+        r <-  lggL (tlhss ++ [rhss])
hunk ./src/Igor2/RuleDevelopment/Matching.hs 11
+import Control.Arrow ((***))
hunk ./src/Igor2/RuleDevelopment/Matching.hs 17
-import Igor2.Data.Rules
+import qualified Igor2.Data.Rules as Rules
hunk ./src/Igor2/RuleDevelopment/Matching.hs 64
-
hunk ./src/Igor2/RuleDevelopment/Matching.hs 95
-                        mapM (mkIndirectCall cr n) $ sequence m
+                        eitherMatchings <- applyC $ computeMatchings m
+                        case eitherMatchings of
+                            Left errmsg     -> error $ "Unexpected error in computeMatchings: " ++ errmsg
+                            Right matchings -> mapM (mkIndirectCall cr n) $ matchings
hunk ./src/Igor2/RuleDevelopment/Matching.hs 104
+-- TODO: Maybe replace this by (Monad m, MonadError m e) => m
+type MatchingErrorMonad = Either String
+
+-- Switch between allMatchings and bestMatchings
+computeMatchings :: [[(Ordering, [Rule])]] -> C MatchingErrorMonad [(Ordering, [[Rule]])]
+computeMatchings ioMatrix =
+    let all_matchings = allMatchings ioMatrix
+        best_matchings = bestMatchings ioMatrix
+    in do bm <- best_matchings
+          if null bm
+              then all_matchings
+              else return bm
+
+{-| Computes all possible matchings from an IO matrix, where each inner list of
+    type [(Ordering, [Rule])] corresponds to one caller IO example. In the result,
+    each inner list of type [[Rule]] contains exactly one element of each previous
+    inner list - i.e., it's the cross-product of all inner lists.
+-}
+allMatchings :: [[(Ordering, [Rule])]] -> C MatchingErrorMonad [(Ordering, [[Rule]])]
+allMatchings = return . (map (\ios -> (maximum $ map fst ios, transpose $ map snd ios))) . sequence
+
+bestMatchings :: [[(Ordering, [Rule])]] -> C MatchingErrorMonad [(Ordering, [[Rule]])]
+bestMatchings = bestMatchings' (LT, [])
+
+{-
+    All ArgLists have the same length (during one call from bestMatchings),
+    namely the number of arguments of the target function (callee); the ith
+    list entry always corresponds to the ith argument.
+
+    A FunList is a collection of io examples which will be used to create a new
+    function via addIO (in mkIndirectCall).
+-}
+type ArgList a = [a]
+type FunList = [Rule]
+bestMatchings' :: (Ordering, ArgList FunList)
+               -> [[(Ordering, ArgList Rule)]]
+               -> C MatchingErrorMonad [(Ordering, ArgList FunList)]
+bestMatchings' hist []       = do return [hist]
+bestMatchings' hist (xs:xxs) =
+    concatMapM (\(o, rs) ->
+        let nhist = (max o *** multiCons rs) hist
+        in do allClosed <- liftM and $ mapM (liftM Rules.isClosed . lggRules) (snd nhist)
+              if allClosed
+                then bestMatchings' nhist xxs
+                else return []
+    ) xs
+
+{-| This is nearly like zipWith (:), except when the two arguments don't have
+    the same length. The second argument is not allowed to be longer (this will
+    result in a pattern match failure). If the first argument is longer, the
+    second is padded with [].
+-}
+multiCons :: [a] -> [[a]] -> [[a]]
+multiCons []     []     = []
+multiCons (x:xs) []     = [x]   : multiCons xs []
+multiCons (x:xs) (y:ys) = (x:y) : multiCons xs ys
+
+concatMapM :: (Monad m) => (a -> m [b]) -> [a] -> m [b]
+concatMapM f = liftM concat . mapM f
+
hunk ./src/Igor2/RuleDevelopment/Matching.hs 231
-mkIndirectCall :: CovrRule -> Name -> [(Ordering, [Rule])] -> IM (CovrRules,[Call])
+mkIndirectCall :: CovrRule -> Name -> (Ordering, [[Rule]]) -> IM (CovrRules,[Call])
hunk ./src/Igor2/RuleDevelopment/Matching.hs 233
-    let subargsio = transpose $ map snd ios
-    subfns        <- mapM (addIO.rules) subargsio
-    let subftys   = map (typeOf.rhs.head) subargsio
-    let subcalls  = map (\(n,ty) -> mkCall n ty (lhs.crul $ cr)) (zip subfns subftys)
+    -- subargsio contains a list of rules for each argument of tgtn, one rule
+    -- (in each inner list) for each of cr's IO examples.
+    let subargsio = snd ios
+    subfns        <- mapM (addIO . rules) subargsio
+    let subftys   = map (typeOf . rhs . head) subargsio
+    let subcalls  = map (\(n, ty) -> mkCall n ty (lhs $ crul cr)) (zip subfns subftys)
hunk ./src/Igor2/RuleDevelopment/Matching.hs 241
-    let call      = ((name cr),tgtn, maximum (map fst ios)) -- call to target
-    let calls  = map (\n -> (tgtn,n,EQ)) subfns             -- auxiliary calls
+    let call      = ((name cr), tgtn, fst ios)              -- call to target
+    let calls     = map (\n -> (tgtn, n, EQ)) subfns        -- auxiliary calls
hunk ./src/Igor2/RuleDevelopment/Matching.hs 276
---   'o'.
+--   'o'. Each IO pair will be used in a different function (added in
+--   mkIndirectCall), each of which computes the respective argument of the
+--   function tgt belongs to.