module MPS.Snippets where import MPS.Hack.Dot import Prelude hiding ((.), sum, product, maximum, minimum, foldl, foldr, foldl1, foldr1, concat, concatMap, and, or, any, all, elem, (^)) import qualified Prelude as Prelude import Control.Arrow ((&&&), (>>>)) import Control.Monad hiding (join) import Control.Parallel import Data.Char import Data.Maybe import Data.Graph.Inductive (Gr, mkGraph) import Data.Foldable import Data.Time.Clock.POSIX import Data.Time import Data.List (transpose, sort, group, (\\), sortBy) import qualified Data.Array as A import qualified Data.List as L import qualified Data.Set as S import qualified Data.Graph as G import qualified Data.Map as M import qualified Data.ByteString.Lazy.Char8 as B import System.Locale import System.Posix.Files import System.IO import System.Directory import qualified System.IO.Unsafe as Unsafe import Test.QuickCheck import Text.RegexPR import Text.Pandoc import Text.Template import Text.InterpolatedString.QQ import Text.ParserCombinators.Parsec (many, char, many1, digit, (<|>), Parser, anyChar, try) import qualified Text.ParserCombinators.Parsec as P import Codec.Binary.Base64.String as C import qualified Codec.Binary.UTF8.String as Codec import qualified Codec.Compression.GZip as GZip import Debug.Trace import Numeric -- List join x xs = L.intercalate x xs join' xs = xs.concat first = head -- Set requires Ord instance, so use nub when -- xs is not comparable unique xs = xs.to_set.to_list is_unique xs = xs.unique.length == xs.length same xs = xs.unique.length == 1 times = flip replicate upto m n = flip enumFromTo m n downto m n = [n, n-1.. m] remove_at n xs = xs.take n ++ xs.drop (n+1) insert_at n x xs = splitted.fst ++ [x] ++ splitted.snd where splitted = xs.splitAt n replace_at n x xs = xs.take n ++ [x] ++ xs.drop (n+1) at i xs = xs !! i slice l r xs = xs.take r.drop l cherry_pick ids xs = ids.map(xs !!) reduce f xs = foldl1 f xs reduce' f (x:xs) = inject' x f xs reduce' _ _ = error "reduce' takes a list of at least 2 elements" inject init f xs = foldl f init xs inject' init f xs = foldl' f init xs none_of f xs = not $ any f xs select = filter reject f = filter(not ... f) lookup' i xs = xs.lookup i .fromJust inner_map f xs = xs.map(map f) inner_reduce f xs = xs.map(reduce f) inner_inject init f xs = xs.map(inject init f) label_by f xs = xs.map(f &&& id) labeling f xs = xs.map(id &&& f) in_group_of _ [] = [] in_group_of n xs = h : t.in_group_of(n) where (h, t) = xs.splitAt(n) split_to n xs = xs.in_group_of(size) where l = xs.length size = if l < n then 1 else l `div` n apply x f = f x send_to = apply let_receive f s = flip f s map_send_to x fs = fs.map(send_to(x)) belongs_to xs x = xs.elem x has xs x = flip belongs_to xs x indexed xs = xs.zip([0..]) map_with_index f xs = xs.indexed.map(f) ljust n x xs | n < xs.length = xs | otherwise = ( n.times x ++ xs ).reverse.take n.reverse rjust n x xs | n < xs.length = xs | otherwise = ( xs ++ n.times x ).take n ub = takeWhile lb f = dropWhile ( not ... f ) between a b xs = xs.lb a .ub b not_null xs = xs.null.not powerslice xs = [ xs.slice j (j+i) | i <- l.downto 1, j <- [0..l - i] ] where l = xs.length -- only works for sorted list -- but could be infinite -- e.g. a `common` b `common` c common _ [] = [] common [] _ = [] common a@(x:xs) b@(y:ys) | x .is y = y : common xs b | x < y = common xs b | otherwise = common a ys -- faster reverse sort rsort xs = xs.L.sortBy(\a b -> b `compare` a) encode xs = xs.group.map (length &&& head) decode xs = xs.map(\(l,x) -> l.times x).join' only_one [_] = True only_one _ = False concat_map f xs = concatMap f xs -- Map to_h xs = xs.M.fromList -- QuickCheck quick_check prop = quickCheck prop qc prop = quick_check prop -- BackPorts on :: (b -> b -> c) -> (a -> b) -> a -> a -> c (*) `on` f = \x y -> f x * f y -- Ord compare_by f = on compare f eq b a = (==) a b is a b = eq a b is_not a b = not (is a b) -- Tuple swap (x,y) = (y,x) tuple2 xs = (xs.first, xs.last) tuple3 xs = (xs.first, xs.tail.first, xs.last) list2 (x,y) = [x,y] list3 (x,y,z) = [x,y,z] filter_fst f = filter(\(a,_) -> a.f) filter_snd f = filter(\(_,b) -> b.f) only_fst = map(\(a,_) -> a) only_snd = map(\(_,b) -> b) map_fst f = map(\(a,b) -> (a.f, b)) map_snd f = map(\(a,b) -> (a, b.f)) pair f a b = f (a,b) triple f a b c = f (a,b,c) splash f (a,b) = f a b splash3 f (a,b,c) = f a b c twin x = (x,x) -- Control.Arrow merge f = map (pair f) -- IO purify = Unsafe.unsafePerformIO read_pure x = x.readFile.purify write_pure file c = writeFile file c -- Parallel p_eval xs = xs.par(xs.reduce(par)) p_reduce op xs = xs.p_eval.reduce(op) p_map op xs = xs.map(op).p_eval p_eval' xs = xs.pseq( xs.reduce par ) p_reduce' op xs = xs.p_eval'.reduce op p_map' op xs = xs.map op .p_eval' p_split_to n xs = xs.in_group_of(n).L.transpose p_map_reduce_to n m r xs = xs.split_to n .map m .p_reduce' r p_map_reduce m r xs = p_map_reduce_to 16 m r xs -- Matrix row n i = i `div` n col n i = i `mod` n m !!! i = m.at(row n i) .at(col n i) where n = m.first.length -- Runtime -- eval_with libs s = Eval.unsafeEval s libs.purify.fromJust -- eval s = eval_with s [] -- Date date = fromGregorian splash_date = toGregorian -- String split re xs | xs.match re .isJust = splitRegexPR re xs .reject empty | otherwise = [xs] split' s = s.lines.reject empty sub = subRegexPR gsub = gsubRegexPR match = matchRegexPR strip s = s.sub "^\\s*" "" .reverse .sub "^\\s*" "" .reverse empty s = case s.match("\\S") of Just _ -> False Nothing -> True to_s x = x.show -- Var is_palindrom s = s.reverse.is(s) -- Integer collapse' [] _ r = r collapse' (x:xs) q r = collapse' xs (q+1) (r + x * 10 <^> q) collapse xs = collapse' (xs.reverse.map from_i) 0 0 .fromIntegral explode n = n.show.map digitToInt base p n = showIntAtBase p intToDigit n "" from_i n = fromIntegral n int_square n = n.fromIntegral.sqrt.round :: Integer -- Fold to_list xs = toList xs -- Set to_set xs = xs.S.fromList -- Array to_a xs = xs.A.listArray (0, xs.length - 1) to_a' i xs = A.listArray i xs hist bnds ns = A.accumArray (+) 0 bnds [(n, 1) | n <- ns, A.inRange bnds n] -- Graph1 to_g'' = G.buildG -- Graph2 type GType = Int to_g_with :: Real a => (GType -> c) -> [(GType, GType, a)] -> Gr c a to_g_with mapper xs = mkGraph (xs.label_nodes) xs where node_pair x = (x, mapper x) label_nodes xs = xs.map(\(a,b,_) -> [a,b]) .join' .unique .map node_pair to_g xs = to_g_with id xs graph_map xs = (edges, vertex_map) where vertices = xs.map(\(a,b,_)-> [a,b]).join'.unique.sort vertex_map = vertices.indexed r_vertex_map = vertex_map.map(swap) edges = xs.map(\(a,b,c) -> (r_vertex_map.lookup' a, r_vertex_map.lookup' b, c)) to_g' xs = let (edges, vertex_map) = graph_map xs in edges.to_g_with (vertex_map.flip lookup') -- Parser parse p s = case (P.parse p "" s) of Left err -> err.show.error Right x -> x -- Algorithm -- DP -- OK usage is a bit tricky -- xs.cache block where -- block a list = closure -- The idea is to bound a in your closure -- what is this a anyway? -- It's an array that lazily caches the result -- from your list processing function, i.e. what's -- inside your closure. -- This implies that your processing function -- is of type: [x] -> [x] cache f xs = a.to_list where a = xs.g.to_a g ys = f a ys -- Greedy greedy_count x xs = greedy x xs .length greedy x xs = greedy' x (xs.rsort) where greedy' x _ | x < 0 = [[]] greedy' 0 _ = [[]] greedy' x [y] = if (x `mod` y) .is 0 then [ (x `div` y).from_i .times y ] else [[]] greedy' s (a:as) = [ h ++ t | n <- [0..(div s a)].reverse, let h = n.from_i.times a, t <- greedy' (s - n * a) as, let c = h ++ t, c.sum == s ] greedy' _ _ = error "argument type" -- Debug trace' x = trace (x.show) x -- Text markdown = b2u >>> readMarkdown defaultParserState >>> writeHtml defaultWriterOptions markdown' = b2u >>> readMarkdown defaultParserState >>> writeHtmlString defaultWriterOptions >>> u2b -- Monad a ^ b = a .liftM b infixl 9 ^ (<^>) = (Prelude.^) infixr 8 <^> a <.> b = a .liftM b infixl 9 <.> -- String lower = map toLower upper = map toUpper starts_with [] _ = True starts_with _ [] = False starts_with (x:xs) (y:ys) | x == y = starts_with xs ys | otherwise = False ends_with x y = starts_with (x.reverse) (y.reverse) capitalize [] = [] capitalize (x:xs) = [x].upper ++ xs.lower camel_case = split "_" >>> map capitalize >>> join' snake_case = gsub "\\B[A-Z]" "_\\&" >>> lower -- XML unicode_char :: Parser Char unicode_char = do char '&' char '#' word <- many1 digit char ';' return $ chr (read word) unescape_parser :: Parser String unescape_parser = many (try unicode_char <|> anyChar) unescape_unicode_xml s = parse unescape_parser s escape_unicode_xml :: String -> String escape_unicode_xml = concatMap fixChar where fixChar '<' = "<" fixChar '>' = ">" fixChar '&' = "&" fixChar '"' = "\"" fixChar c | ord c < 0x80 = [c] fixChar c = "&#" ++ show (ord c) ++ ";" -- IO ls s = getDirectoryContents s <.> (\\ [".", ".."]) file_size :: String -> IO Integer file_size path = withFile (path.u2b) ReadMode hFileSize file_mtime :: String -> IO UTCTime file_mtime path = getFileStatus (path.u2b) ^ modificationTime ^ realToFrac ^ posixSecondsToUTCTime read_binary_file :: String -> IO String read_binary_file path = path.u2b.B.readFile ^ B.unpack get_permissions :: String -> IO Permissions get_permissions path = getPermissions (path.u2b) get_current_directory :: IO String get_current_directory = getCurrentDirectory ^ b2u -- Text filter_comment = lines >>> map strip >>> reject null >>> reject (head >>> (== '#')) >>> unlines interpolate :: String -> [(String, String)] -> String interpolate s params = B.unpack $ substitute (B.pack s) (context params) where context = map packPair >>> to_h packPair (x, y) = (B.pack x, B.pack y) -- Time now :: IO UTCTime now = getCurrentTime format_time :: String -> UTCTime -> String format_time = formatTime defaultTimeLocale -- UTF8 b2u = Codec.decodeString u2b = Codec.encodeString -- QQ here = istr -- compress zip64, unzip64 :: String -> String zip64 = B.pack >>> GZip.compress >>> B.unpack >>> C.encode unzip64 = C.decode >>> B.pack >>> GZip.decompress >>> B.unpack