module MagicHaskeller.Individual(availableNames, prioritizedNamesToPg) where
import Language.Haskell.TH as TH
import qualified Data.Map as M
import qualified Data.IntMap as I
import Data.Char(isDigit)
import Data.List(findIndex, findIndices, mapAccumL, mapAccumR)
import Data.Generics
import MagicHaskeller.LibTH
import MagicHaskeller.Types(size)
import MagicHaskeller.ProgGenSF(mkTrieOptSFIO)
import Prelude hiding (tail)
totals :: [Primitive]
totals = concat withDoubleRatio
partials :: [(Primitive,Primitive)]
partials = concat tupartialssNormal
aliases :: [(String, [Primitive])]
aliases = [ ("total init", $(p [| reverse . drop 1 . reverse :: [a] -> [a] |])),
("total head", $(p [| foldr const :: a -> (->) [a] a |])),
("total last", $(p [| last' :: a -> [a] -> a |])),
("drop 1", $(p [| tail :: (->) [a] [a] |] )),
("foldl", $(p [| flip . flip foldl :: a -> (->) [b] ((a -> b -> a) -> a) |])),
("foldr", $(p [| flip . flip foldr :: a -> (->) [b] ((b -> a -> a) -> a) |])),
("maybe", $(p [| flip . maybe :: a -> (->) (Maybe b) ((b -> a) -> a) |])),
("map", $(p [| flip map :: (->) ([a]) ((a -> b) -> [b]) |])),
("concatMap", $(p [| flip concatMap :: (->) ([a]) ((a -> [b]) -> [b]) |])),
("any", $(p [| flip any :: (->) ([a]) ((a -> Bool) -> Bool) |])),
("all", $(p [| flip all :: (->) ([a]) ((a -> Bool) -> Bool) |])),
("zipWith", $(p [| flip . flip zipWith :: (->) ([a]) ((->) ([b]) ((a -> b -> c) -> [c])) |])),
("either", $(p [| flip (flip . either) :: (->) (Either a b) ((a -> c) -> (b -> c) -> c) |])),
("uncurry", $(p [| flip uncurry :: (->) ((a, b)) ((a -> b -> c) -> c) |])),
("findIndex", $(p [| flip findIndex :: (->) ([a]) ((a -> Bool) -> Maybe Int) |])),
("findIndices",$(p [| flip findIndices :: (->) ([a]) ((a -> Bool) -> [Int]) |])),
("mapAccumL", $(p [| flip . flip mapAccumL :: acc -> (->) ([x]) ((acc -> x -> (acc, y)) -> (acc, [y])) |])),
("mapAccumR", $(p [| flip . flip mapAccumR :: acc -> (->) ([x]) ((acc -> x -> (acc, y)) -> (acc, [y])) |])),
("\\n x f -> iterate f x !! (n::Int)", $(p [| nat_cata :: (->) Int (a -> (a -> a) -> a) |])),
("\\n x f -> iterate f x !! (n::Integer)", $(p [| nat_cata :: (->) Integer (a -> (a -> a) -> a) |]))
]
normalizeSpaces = unwords . words
mapAvailables :: M.Map String (Either [Primitive] (Primitive,Primitive))
mapAvailables = M.fromList assocAvailables
assocAvailables = [ (normalizeSpaces s, Left prims) | (s, prims) <- aliases ] ++ [ (pprintPrim prim, Left [prim]) | prim <- totals ] ++ [ (pprintPrim prim, Right tup) | tup@(_,prim) <- partials ]
availableNames :: [String]
availableNames = map fst assocAvailables
pprintPrim :: Primitive -> String
pprintPrim (_, e@(VarE name), t) =
case nameBase name of
('b':'y':d:'_':name) | isDigit d -> name
('-':'-':'#':name) -> '(':dropWhile (=='#') name ++")"
_ -> normalizeSpaces $ pprint $ TH.SigE (simplify e) t
pprintPrim (_, e, t) = normalizeSpaces $ pprint $ TH.SigE (simplify e) t
simplify :: TH.Exp -> TH.Exp
simplify = everywhere (mkT simp)
simp (ConE name) = ConE $ mkName $ nameBase name
simp (VarE name) = VarE $ mkName $ nameBase name
simp e = e
namesToPrimitives :: [String] -> ([Primitive], [(Primitive,Primitive)])
namesToPrimitives xss = let ets = map ((mapAvailables !!!) . normalizeSpaces) xss
in ([ prim | Left prims <- ets, prim <- prims], [ tup | Right tup <- ets])
a !!! b = case M.lookup b a of Nothing -> error $ "!!! "++b
Just x -> x
namessToPrimitives :: [[String]] -> ([[Primitive]], [[(Primitive,Primitive)]])
namessToPrimitives nss = unzip $ map namesToPrimitives nss
prioritizedNamesToNamess :: [(Int,String)] -> [[String]]
prioritizedNamesToNamess ts = let mapPriorName = I.fromListWith (++) [(i,[s]) | (i,s) <- ts]
in map (\i -> maybe [] id $ I.lookup i mapPriorName) [fst $ I.findMin mapPriorName .. fst $ I.findMax mapPriorName]
prioritizedNamesToPg :: Maybe Int -> [(Int,String)] -> IO ProgGenSF
prioritizedNamesToPg Nothing ts = pNTP options ts
prioritizedNamesToPg (Just sz) ts = pNTP options{memoCondPure = \t d -> size t < sz && 0<d } ts
pNTP opt ts = mkPGXOpts mkTrieOptSFIO opt{tv1=True,nrands=repeat 20,timeout=Just 20000} (eqs++ords++doubleCls++ratioCls) clspartialss tot part
where (tot,part) = namessToPrimitives $ prioritizedNamesToNamess ts