{-# LANGUAGE CPP #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE BangPatterns #-}
#if __GLASGOW_HASKELL__ < 800
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE FlexibleContexts #-}
#endif
module Util (
ghciSupported, debugIsOn, ncgDebugIsOn,
ghciTablesNextToCode,
isWindowsHost, isDarwinHost,
zipEqual, zipWithEqual, zipWith3Equal, zipWith4Equal,
zipLazy, stretchZipWith, zipWithAndUnzip,
zipWithLazy, zipWith3Lazy,
filterByList, filterByLists, partitionByList,
unzipWith,
mapFst, mapSnd, chkAppend,
mapAndUnzip, mapAndUnzip3, mapAccumL2,
nOfThem, filterOut, partitionWith, splitEithers,
dropWhileEndLE, spanEnd,
foldl1', foldl2, count, all2,
lengthExceeds, lengthIs, lengthAtLeast,
listLengthCmp, atLength,
equalLength, compareLength, leLength,
isSingleton, only, singleton,
notNull, snocView,
isIn, isn'tIn,
chunkList,
changeLast,
fstOf3, sndOf3, thdOf3,
firstM, first3M,
fst3, snd3, third3,
uncurry3,
liftFst, liftSnd,
takeList, dropList, splitAtList, split,
dropTail, capitalise,
nTimes,
sortWith, minWith, nubSort,
isEqual, eqListBy, eqMaybeBy,
thenCmp, cmpList,
removeSpaces,
(<&&>), (<||>),
fuzzyMatch, fuzzyLookup,
transitiveClosure,
seqList,
looksLikeModuleName,
looksLikePackageName,
getCmd, toCmdArgs, toArgs,
exactLog2,
readRational,
maybeRead, maybeReadFuzzy,
doesDirNameExist,
getModificationUTCTime,
modificationTimeIfExists,
hSetTranslit,
global, consIORef, globalM,
sharedGlobal, sharedGlobalM,
Suffix,
splitLongestPrefix,
escapeSpaces,
Direction(..), reslash,
makeRelativeTo,
abstractConstr, abstractDataType, mkNoRepType,
charToC,
hashString,
#if MIN_VERSION_GLASGOW_HASKELL(7,10,2,0)
GHC.Stack.CallStack,
#endif
HasCallStack,
HasDebugCallStack,
prettyCurrentCallStack,
OverridingBool(..),
overrideWith,
) where
#include "HsVersions.h"
import Exception
import Panic
import Data.Data
import Data.IORef ( IORef, newIORef, atomicModifyIORef' )
import System.IO.Unsafe ( unsafePerformIO )
import Data.List hiding (group)
import GHC.Exts
import qualified GHC.Stack
import Control.Applicative ( liftA2 )
import Control.Monad ( liftM )
import GHC.IO.Encoding (mkTextEncoding, textEncodingName)
import GHC.Conc.Sync ( sharedCAF )
import System.IO (Handle, hGetEncoding, hSetEncoding)
import System.IO.Error as IO ( isDoesNotExistError )
import System.Directory ( doesDirectoryExist, getModificationTime )
import System.FilePath
import Data.Char ( isUpper, isAlphaNum, isSpace, chr, ord, isDigit, toUpper)
import Data.Int
import Data.Ratio ( (%) )
import Data.Ord ( comparing )
import Data.Bits
import Data.Word
import qualified Data.IntMap as IM
import qualified Data.Set as Set
import Data.Time
infixr 9 `thenCmp`
ghciSupported :: Bool
#ifdef GHCI
ghciSupported = True
#else
ghciSupported = False
#endif
debugIsOn :: Bool
#ifdef DEBUG
debugIsOn = True
#else
debugIsOn = False
#endif
ncgDebugIsOn :: Bool
#ifdef NCG_DEBUG
ncgDebugIsOn = True
#else
ncgDebugIsOn = False
#endif
ghciTablesNextToCode :: Bool
#ifdef GHCI_TABLES_NEXT_TO_CODE
ghciTablesNextToCode = True
#else
ghciTablesNextToCode = False
#endif
isWindowsHost :: Bool
#ifdef mingw32_HOST_OS
isWindowsHost = True
#else
isWindowsHost = False
#endif
isDarwinHost :: Bool
#ifdef darwin_HOST_OS
isDarwinHost = True
#else
isDarwinHost = False
#endif
nTimes :: Int -> (a -> a) -> (a -> a)
nTimes 0 _ = id
nTimes 1 f = f
nTimes n f = f . nTimes (n-1) f
fstOf3 :: (a,b,c) -> a
sndOf3 :: (a,b,c) -> b
thdOf3 :: (a,b,c) -> c
fstOf3 (a,_,_) = a
sndOf3 (_,b,_) = b
thdOf3 (_,_,c) = c
fst3 :: (a -> d) -> (a, b, c) -> (d, b, c)
fst3 f (a, b, c) = (f a, b, c)
snd3 :: (b -> d) -> (a, b, c) -> (a, d, c)
snd3 f (a, b, c) = (a, f b, c)
third3 :: (c -> d) -> (a, b, c) -> (a, b, d)
third3 f (a, b, c) = (a, b, f c)
uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
uncurry3 f (a, b, c) = f a b c
liftFst :: (a -> b) -> (a, c) -> (b, c)
liftFst f (a,c) = (f a, c)
liftSnd :: (a -> b) -> (c, a) -> (c, b)
liftSnd f (c,a) = (c, f a)
firstM :: Monad m => (a -> m c) -> (a, b) -> m (c, b)
firstM f (x, y) = liftM (\x' -> (x', y)) (f x)
first3M :: Monad m => (a -> m d) -> (a, b, c) -> m (d, b, c)
first3M f (x, y, z) = liftM (\x' -> (x', y, z)) (f x)
filterOut :: (a->Bool) -> [a] -> [a]
filterOut _ [] = []
filterOut p (x:xs) | p x = filterOut p xs
| otherwise = x : filterOut p xs
partitionWith :: (a -> Either b c) -> [a] -> ([b], [c])
partitionWith _ [] = ([],[])
partitionWith f (x:xs) = case f x of
Left b -> (b:bs, cs)
Right c -> (bs, c:cs)
where (bs,cs) = partitionWith f xs
splitEithers :: [Either a b] -> ([a], [b])
splitEithers [] = ([],[])
splitEithers (e : es) = case e of
Left x -> (x:xs, ys)
Right y -> (xs, y:ys)
where (xs,ys) = splitEithers es
chkAppend :: [a] -> [a] -> [a]
chkAppend xs ys
| null ys = xs
| otherwise = xs ++ ys
zipEqual :: String -> [a] -> [b] -> [(a,b)]
zipWithEqual :: String -> (a->b->c) -> [a]->[b]->[c]
zipWith3Equal :: String -> (a->b->c->d) -> [a]->[b]->[c]->[d]
zipWith4Equal :: String -> (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]
#ifndef DEBUG
zipEqual _ = zip
zipWithEqual _ = zipWith
zipWith3Equal _ = zipWith3
zipWith4Equal _ = zipWith4
#else
zipEqual _ [] [] = []
zipEqual msg (a:as) (b:bs) = (a,b) : zipEqual msg as bs
zipEqual msg _ _ = panic ("zipEqual: unequal lists:"++msg)
zipWithEqual msg z (a:as) (b:bs)= z a b : zipWithEqual msg z as bs
zipWithEqual _ _ [] [] = []
zipWithEqual msg _ _ _ = panic ("zipWithEqual: unequal lists:"++msg)
zipWith3Equal msg z (a:as) (b:bs) (c:cs)
= z a b c : zipWith3Equal msg z as bs cs
zipWith3Equal _ _ [] [] [] = []
zipWith3Equal msg _ _ _ _ = panic ("zipWith3Equal: unequal lists:"++msg)
zipWith4Equal msg z (a:as) (b:bs) (c:cs) (d:ds)
= z a b c d : zipWith4Equal msg z as bs cs ds
zipWith4Equal _ _ [] [] [] [] = []
zipWith4Equal msg _ _ _ _ _ = panic ("zipWith4Equal: unequal lists:"++msg)
#endif
zipLazy :: [a] -> [b] -> [(a,b)]
zipLazy [] _ = []
zipLazy (x:xs) ~(y:ys) = (x,y) : zipLazy xs ys
zipWithLazy :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWithLazy _ [] _ = []
zipWithLazy f (a:as) ~(b:bs) = f a b : zipWithLazy f as bs
zipWith3Lazy :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
zipWith3Lazy _ [] _ _ = []
zipWith3Lazy f (a:as) ~(b:bs) ~(c:cs) = f a b c : zipWith3Lazy f as bs cs
filterByList :: [Bool] -> [a] -> [a]
filterByList (True:bs) (x:xs) = x : filterByList bs xs
filterByList (False:bs) (_:xs) = filterByList bs xs
filterByList _ _ = []
filterByLists :: [Bool] -> [a] -> [a] -> [a]
filterByLists (True:bs) (x:xs) (_:ys) = x : filterByLists bs xs ys
filterByLists (False:bs) (_:xs) (y:ys) = y : filterByLists bs xs ys
filterByLists _ _ _ = []
partitionByList :: [Bool] -> [a] -> ([a], [a])
partitionByList = go [] []
where
go trues falses (True : bs) (x : xs) = go (x:trues) falses bs xs
go trues falses (False : bs) (x : xs) = go trues (x:falses) bs xs
go trues falses _ _ = (reverse trues, reverse falses)
stretchZipWith :: (a -> Bool) -> b -> (a->b->c) -> [a] -> [b] -> [c]
stretchZipWith _ _ _ [] _ = []
stretchZipWith p z f (x:xs) ys
| p x = f x z : stretchZipWith p z f xs ys
| otherwise = case ys of
[] -> []
(y:ys) -> f x y : stretchZipWith p z f xs ys
mapFst :: (a->c) -> [(a,b)] -> [(c,b)]
mapSnd :: (b->c) -> [(a,b)] -> [(a,c)]
mapFst f xys = [(f x, y) | (x,y) <- xys]
mapSnd f xys = [(x, f y) | (x,y) <- xys]
mapAndUnzip :: (a -> (b, c)) -> [a] -> ([b], [c])
mapAndUnzip _ [] = ([], [])
mapAndUnzip f (x:xs)
= let (r1, r2) = f x
(rs1, rs2) = mapAndUnzip f xs
in
(r1:rs1, r2:rs2)
mapAndUnzip3 :: (a -> (b, c, d)) -> [a] -> ([b], [c], [d])
mapAndUnzip3 _ [] = ([], [], [])
mapAndUnzip3 f (x:xs)
= let (r1, r2, r3) = f x
(rs1, rs2, rs3) = mapAndUnzip3 f xs
in
(r1:rs1, r2:rs2, r3:rs3)
zipWithAndUnzip :: (a -> b -> (c,d)) -> [a] -> [b] -> ([c],[d])
zipWithAndUnzip f (a:as) (b:bs)
= let (r1, r2) = f a b
(rs1, rs2) = zipWithAndUnzip f as bs
in
(r1:rs1, r2:rs2)
zipWithAndUnzip _ _ _ = ([],[])
mapAccumL2 :: (s1 -> s2 -> a -> (s1, s2, b)) -> s1 -> s2 -> [a] -> (s1, s2, [b])
mapAccumL2 f s1 s2 xs = (s1', s2', ys)
where ((s1', s2'), ys) = mapAccumL (\(s1, s2) x -> case f s1 s2 x of
(s1', s2', y) -> ((s1', s2'), y))
(s1, s2) xs
nOfThem :: Int -> a -> [a]
nOfThem n thing = replicate n thing
atLength :: ([a] -> b)
-> b
-> [a]
-> Int
-> b
atLength atLenPred atEnd ls0 n0
| n0 < 0 = atLenPred ls0
| otherwise = go n0 ls0
where
go 0 ls = atLenPred ls
go _ [] = atEnd
go n (_:xs) = go (n-1) xs
lengthExceeds :: [a] -> Int -> Bool
lengthExceeds lst n
| n < 0
= True
| otherwise
= atLength notNull False lst n
lengthAtLeast :: [a] -> Int -> Bool
lengthAtLeast = atLength (const True) False
lengthIs :: [a] -> Int -> Bool
lengthIs lst n
| n < 0
= False
| otherwise
= atLength null False lst n
listLengthCmp :: [a] -> Int -> Ordering
listLengthCmp = atLength atLen atEnd
where
atEnd = LT
atLen [] = EQ
atLen _ = GT
equalLength :: [a] -> [b] -> Bool
equalLength [] [] = True
equalLength (_:xs) (_:ys) = equalLength xs ys
equalLength _ _ = False
compareLength :: [a] -> [b] -> Ordering
compareLength [] [] = EQ
compareLength (_:xs) (_:ys) = compareLength xs ys
compareLength [] _ = LT
compareLength _ [] = GT
leLength :: [a] -> [b] -> Bool
leLength xs ys = case compareLength xs ys of
LT -> True
EQ -> True
GT -> False
singleton :: a -> [a]
singleton x = [x]
isSingleton :: [a] -> Bool
isSingleton [_] = True
isSingleton _ = False
notNull :: [a] -> Bool
notNull [] = False
notNull _ = True
only :: [a] -> a
#ifdef DEBUG
only [a] = a
#else
only (a:_) = a
#endif
only _ = panic "Util: only"
isIn, isn'tIn :: Eq a => String -> a -> [a] -> Bool
# ifndef DEBUG
isIn _msg x ys = x `elem` ys
isn'tIn _msg x ys = x `notElem` ys
# else /* DEBUG */
isIn msg x ys
= elem100 0 x ys
where
elem100 :: Eq a => Int -> a -> [a] -> Bool
elem100 _ _ [] = False
elem100 i x (y:ys)
| i > 100 = trace ("Over-long elem in " ++ msg) (x `elem` (y:ys))
| otherwise = x == y || elem100 (i + 1) x ys
isn'tIn msg x ys
= notElem100 0 x ys
where
notElem100 :: Eq a => Int -> a -> [a] -> Bool
notElem100 _ _ [] = True
notElem100 i x (y:ys)
| i > 100 = trace ("Over-long notElem in " ++ msg) (x `notElem` (y:ys))
| otherwise = x /= y && notElem100 (i + 1) x ys
# endif /* DEBUG */
chunkList :: Int -> [a] -> [[a]]
chunkList _ [] = []
chunkList n xs = as : chunkList n bs where (as,bs) = splitAt n xs
changeLast :: [a] -> a -> [a]
changeLast [] _ = panic "changeLast"
changeLast [_] x = [x]
changeLast (x:xs) x' = x : changeLast xs x'
minWith :: Ord b => (a -> b) -> [a] -> a
minWith get_key xs = ASSERT( not (null xs) )
head (sortWith get_key xs)
nubSort :: Ord a => [a] -> [a]
nubSort = Set.toAscList . Set.fromList
transitiveClosure :: (a -> [a])
-> (a -> a -> Bool)
-> [a]
-> [a]
transitiveClosure succ eq xs
= go [] xs
where
go done [] = done
go done (x:xs) | x `is_in` done = go done xs
| otherwise = go (x:done) (succ x ++ xs)
_ `is_in` [] = False
x `is_in` (y:ys) | eq x y = True
| otherwise = x `is_in` ys
foldl2 :: (acc -> a -> b -> acc) -> acc -> [a] -> [b] -> acc
foldl2 _ z [] [] = z
foldl2 k z (a:as) (b:bs) = foldl2 k (k z a b) as bs
foldl2 _ _ _ _ = panic "Util: foldl2"
all2 :: (a -> b -> Bool) -> [a] -> [b] -> Bool
all2 _ [] [] = True
all2 p (x:xs) (y:ys) = p x y && all2 p xs ys
all2 _ _ _ = False
count :: (a -> Bool) -> [a] -> Int
count p = go 0
where go !n [] = n
go !n (x:xs) | p x = go (n+1) xs
| otherwise = go n xs
takeList :: [b] -> [a] -> [a]
takeList [] _ = []
takeList (_:xs) ls =
case ls of
[] -> []
(y:ys) -> y : takeList xs ys
dropList :: [b] -> [a] -> [a]
dropList [] xs = xs
dropList _ xs@[] = xs
dropList (_:xs) (_:ys) = dropList xs ys
splitAtList :: [b] -> [a] -> ([a], [a])
splitAtList [] xs = ([], xs)
splitAtList _ xs@[] = (xs, xs)
splitAtList (_:xs) (y:ys) = (y:ys', ys'')
where
(ys', ys'') = splitAtList xs ys
dropTail :: Int -> [a] -> [a]
dropTail n xs
= go (drop n xs) xs
where
go (_:ys) (x:xs) = x : go ys xs
go _ _ = []
dropWhileEndLE :: (a -> Bool) -> [a] -> [a]
dropWhileEndLE p = foldr (\x r -> if null r && p x then [] else x:r) []
spanEnd :: (a -> Bool) -> [a] -> ([a], [a])
spanEnd p l = go l [] [] l
where go yes _rev_yes rev_no [] = (yes, reverse rev_no)
go yes rev_yes rev_no (x:xs)
| p x = go yes (x : rev_yes) rev_no xs
| otherwise = go xs [] (x : rev_yes ++ rev_no) xs
snocView :: [a] -> Maybe ([a],a)
snocView [] = Nothing
snocView xs = go [] xs
where
go acc [x] = Just (reverse acc, x)
go acc (x:xs) = go (x:acc) xs
go _ [] = panic "Util: snocView"
split :: Char -> String -> [String]
split c s = case rest of
[] -> [chunk]
_:rest -> chunk : split c rest
where (chunk, rest) = break (==c) s
capitalise :: String -> String
capitalise [] = []
capitalise (c:cs) = toUpper c : cs
isEqual :: Ordering -> Bool
isEqual GT = False
isEqual EQ = True
isEqual LT = False
thenCmp :: Ordering -> Ordering -> Ordering
{-# INLINE thenCmp #-}
thenCmp EQ ordering = ordering
thenCmp ordering _ = ordering
eqListBy :: (a->a->Bool) -> [a] -> [a] -> Bool
eqListBy _ [] [] = True
eqListBy eq (x:xs) (y:ys) = eq x y && eqListBy eq xs ys
eqListBy _ _ _ = False
eqMaybeBy :: (a ->a->Bool) -> Maybe a -> Maybe a -> Bool
eqMaybeBy _ Nothing Nothing = True
eqMaybeBy eq (Just x) (Just y) = eq x y
eqMaybeBy _ _ _ = False
cmpList :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering
cmpList _ [] [] = EQ
cmpList _ [] _ = LT
cmpList _ _ [] = GT
cmpList cmp (a:as) (b:bs)
= case cmp a b of { EQ -> cmpList cmp as bs; xxx -> xxx }
removeSpaces :: String -> String
removeSpaces = dropWhileEndLE isSpace . dropWhile isSpace
(<&&>) :: Applicative f => f Bool -> f Bool -> f Bool
(<&&>) = liftA2 (&&)
infixr 3 <&&>
(<||>) :: Applicative f => f Bool -> f Bool -> f Bool
(<||>) = liftA2 (||)
infixr 2 <||>
restrictedDamerauLevenshteinDistance :: String -> String -> Int
restrictedDamerauLevenshteinDistance str1 str2
= restrictedDamerauLevenshteinDistanceWithLengths m n str1 str2
where
m = length str1
n = length str2
restrictedDamerauLevenshteinDistanceWithLengths
:: Int -> Int -> String -> String -> Int
restrictedDamerauLevenshteinDistanceWithLengths m n str1 str2
| m <= n
= if n <= 32
then restrictedDamerauLevenshteinDistance' (undefined :: Word32) m n str1 str2
else restrictedDamerauLevenshteinDistance' (undefined :: Integer) m n str1 str2
| otherwise
= if m <= 32
then restrictedDamerauLevenshteinDistance' (undefined :: Word32) n m str2 str1
else restrictedDamerauLevenshteinDistance' (undefined :: Integer) n m str2 str1
restrictedDamerauLevenshteinDistance'
:: (Bits bv, Num bv) => bv -> Int -> Int -> String -> String -> Int
restrictedDamerauLevenshteinDistance' _bv_dummy m n str1 str2
| [] <- str1 = n
| otherwise = extractAnswer $
foldl' (restrictedDamerauLevenshteinDistanceWorker
(matchVectors str1) top_bit_mask vector_mask)
(0, 0, m_ones, 0, m) str2
where
m_ones@vector_mask = (2 ^ m) - 1
top_bit_mask = (1 `shiftL` (m - 1)) `asTypeOf` _bv_dummy
extractAnswer (_, _, _, _, distance) = distance
restrictedDamerauLevenshteinDistanceWorker
:: (Bits bv, Num bv) => IM.IntMap bv -> bv -> bv
-> (bv, bv, bv, bv, Int) -> Char -> (bv, bv, bv, bv, Int)
restrictedDamerauLevenshteinDistanceWorker str1_mvs top_bit_mask vector_mask
(pm, d0, vp, vn, distance) char2
= seq str1_mvs $ seq top_bit_mask $ seq vector_mask $
seq pm' $ seq d0' $ seq vp' $ seq vn' $
seq distance'' $ seq char2 $
(pm', d0', vp', vn', distance'')
where
pm' = IM.findWithDefault 0 (ord char2) str1_mvs
d0' = ((((sizedComplement vector_mask d0) .&. pm') `shiftL` 1) .&. pm)
.|. ((((pm' .&. vp) + vp) .&. vector_mask) `xor` vp) .|. pm' .|. vn
hp' = vn .|. sizedComplement vector_mask (d0' .|. vp)
hn' = d0' .&. vp
hp'_shift = ((hp' `shiftL` 1) .|. 1) .&. vector_mask
hn'_shift = (hn' `shiftL` 1) .&. vector_mask
vp' = hn'_shift .|. sizedComplement vector_mask (d0' .|. hp'_shift)
vn' = d0' .&. hp'_shift
distance' = if hp' .&. top_bit_mask /= 0 then distance + 1 else distance
distance'' = if hn' .&. top_bit_mask /= 0 then distance' - 1 else distance'
sizedComplement :: Bits bv => bv -> bv -> bv
sizedComplement vector_mask vect = vector_mask `xor` vect
matchVectors :: (Bits bv, Num bv) => String -> IM.IntMap bv
matchVectors = snd . foldl' go (0 :: Int, IM.empty)
where
go (ix, im) char = let ix' = ix + 1
im' = IM.insertWith (.|.) (ord char) (2 ^ ix) im
in seq ix' $ seq im' $ (ix', im')
{-# SPECIALIZE INLINE restrictedDamerauLevenshteinDistance'
:: Word32 -> Int -> Int -> String -> String -> Int #-}
{-# SPECIALIZE INLINE restrictedDamerauLevenshteinDistance'
:: Integer -> Int -> Int -> String -> String -> Int #-}
{-# SPECIALIZE restrictedDamerauLevenshteinDistanceWorker
:: IM.IntMap Word32 -> Word32 -> Word32
-> (Word32, Word32, Word32, Word32, Int)
-> Char -> (Word32, Word32, Word32, Word32, Int) #-}
{-# SPECIALIZE restrictedDamerauLevenshteinDistanceWorker
:: IM.IntMap Integer -> Integer -> Integer
-> (Integer, Integer, Integer, Integer, Int)
-> Char -> (Integer, Integer, Integer, Integer, Int) #-}
{-# SPECIALIZE INLINE sizedComplement :: Word32 -> Word32 -> Word32 #-}
{-# SPECIALIZE INLINE sizedComplement :: Integer -> Integer -> Integer #-}
{-# SPECIALIZE matchVectors :: String -> IM.IntMap Word32 #-}
{-# SPECIALIZE matchVectors :: String -> IM.IntMap Integer #-}
fuzzyMatch :: String -> [String] -> [String]
fuzzyMatch key vals = fuzzyLookup key [(v,v) | v <- vals]
fuzzyLookup :: String -> [(String,a)] -> [a]
fuzzyLookup user_entered possibilites
= map fst $ take mAX_RESULTS $ sortBy (comparing snd)
[ (poss_val, distance) | (poss_str, poss_val) <- possibilites
, let distance = restrictedDamerauLevenshteinDistance
poss_str user_entered
, distance <= fuzzy_threshold ]
where
fuzzy_threshold = truncate $ fromIntegral (length user_entered + 2) / (4 :: Rational)
mAX_RESULTS = 3
unzipWith :: (a -> b -> c) -> [(a, b)] -> [c]
unzipWith f pairs = map ( \ (a, b) -> f a b ) pairs
seqList :: [a] -> b -> b
seqList [] b = b
seqList (x:xs) b = x `seq` seqList xs b
global :: a -> IORef a
global a = unsafePerformIO (newIORef a)
consIORef :: IORef [a] -> a -> IO ()
consIORef var x = do
atomicModifyIORef' var (\xs -> (x:xs,()))
globalM :: IO a -> IORef a
globalM ma = unsafePerformIO (ma >>= newIORef)
sharedGlobal :: a -> (Ptr (IORef a) -> IO (Ptr (IORef a))) -> IORef a
sharedGlobal a get_or_set = unsafePerformIO $
newIORef a >>= flip sharedCAF get_or_set
sharedGlobalM :: IO a -> (Ptr (IORef a) -> IO (Ptr (IORef a))) -> IORef a
sharedGlobalM ma get_or_set = unsafePerformIO $
ma >>= newIORef >>= flip sharedCAF get_or_set
looksLikeModuleName :: String -> Bool
looksLikeModuleName [] = False
looksLikeModuleName (c:cs) = isUpper c && go cs
where go [] = True
go ('.':cs) = looksLikeModuleName cs
go (c:cs) = (isAlphaNum c || c == '_' || c == '\'') && go cs
looksLikePackageName :: String -> Bool
looksLikePackageName = all (all isAlphaNum <&&> not . (all isDigit)) . split '-'
getCmd :: String -> Either String
(String, String)
getCmd s = case break isSpace $ dropWhile isSpace s of
([], _) -> Left ("Couldn't find command in " ++ show s)
res -> Right res
toCmdArgs :: String -> Either String
(String, [String])
toCmdArgs s = case getCmd s of
Left err -> Left err
Right (cmd, s') -> case toArgs s' of
Left err -> Left err
Right args -> Right (cmd, args)
toArgs :: String -> Either String
[String]
toArgs str
= case dropWhile isSpace str of
s@('[':_) -> case reads s of
[(args, spaces)]
| all isSpace spaces ->
Right args
_ ->
Left ("Couldn't read " ++ show str ++ " as [String]")
s -> toArgs' s
where
toArgs' :: String -> Either String [String]
toArgs' s = case dropWhile isSpace s of
[] -> Right []
('"' : _) -> do
(arg, rest) <- readAsString s
(arg:) `fmap` toArgs' rest
s' -> case break (isSpace <||> (== '"')) s' of
(argPart1, s''@('"':_)) -> do
(argPart2, rest) <- readAsString s''
((argPart1 ++ show argPart2):) `fmap` toArgs' rest
(arg, s'') -> (arg:) `fmap` toArgs' s''
readAsString :: String -> Either String (String, String)
readAsString s = case reads s of
[(arg, rest)]
| all isSpace (take 1 rest) ->
Right (arg, rest)
_ ->
Left ("Couldn't read " ++ show s ++ " as String")
exactLog2 :: Integer -> Maybe Integer
exactLog2 x
= if (x <= 0 || x >= 2147483648) then
Nothing
else
if (x .&. (-x)) /= x then
Nothing
else
Just (pow2 x)
where
pow2 x | x == 1 = 0
| otherwise = 1 + pow2 (x `shiftR` 1)
readRational__ :: ReadS Rational
readRational__ r = do
(n,d,s) <- readFix r
(k,t) <- readExp s
return ((n%1)*10^^(k-d), t)
where
readFix r = do
(ds,s) <- lexDecDigits r
(ds',t) <- lexDotDigits s
return (read (ds++ds'), length ds', t)
readExp (e:s) | e `elem` "eE" = readExp' s
readExp s = return (0,s)
readExp' ('+':s) = readDec s
readExp' ('-':s) = do (k,t) <- readDec s
return (-k,t)
readExp' s = readDec s
readDec s = do
(ds,r) <- nonnull isDigit s
return (foldl1 (\n d -> n * 10 + d) [ ord d - ord '0' | d <- ds ],
r)
lexDecDigits = nonnull isDigit
lexDotDigits ('.':s) = return (span isDigit s)
lexDotDigits s = return ("",s)
nonnull p s = do (cs@(_:_),t) <- return (span p s)
return (cs,t)
readRational :: String -> Rational
readRational top_s
= case top_s of
'-' : xs -> - (read_me xs)
xs -> read_me xs
where
read_me s
= case (do { (x,"") <- readRational__ s ; return x }) of
[x] -> x
[] -> error ("readRational: no parse:" ++ top_s)
_ -> error ("readRational: ambiguous parse:" ++ top_s)
maybeRead :: Read a => String -> Maybe a
maybeRead str = case reads str of
[(x, "")] -> Just x
_ -> Nothing
maybeReadFuzzy :: Read a => String -> Maybe a
maybeReadFuzzy str = case reads str of
[(x, s)]
| all isSpace s ->
Just x
_ ->
Nothing
doesDirNameExist :: FilePath -> IO Bool
doesDirNameExist fpath = doesDirectoryExist (takeDirectory fpath)
getModificationUTCTime :: FilePath -> IO UTCTime
getModificationUTCTime = getModificationTime
modificationTimeIfExists :: FilePath -> IO (Maybe UTCTime)
modificationTimeIfExists f = do
(do t <- getModificationUTCTime f; return (Just t))
`catchIO` \e -> if isDoesNotExistError e
then return Nothing
else ioError e
hSetTranslit :: Handle -> IO ()
hSetTranslit h = do
menc <- hGetEncoding h
case fmap textEncodingName menc of
Just name | '/' `notElem` name -> do
enc' <- mkTextEncoding $ name ++ "//TRANSLIT"
hSetEncoding h enc'
_ -> return ()
splitLongestPrefix :: String -> (Char -> Bool) -> (String,String)
splitLongestPrefix str pred
| null r_pre = (str, [])
| otherwise = (reverse (tail r_pre), reverse r_suf)
where (r_suf, r_pre) = break pred (reverse str)
escapeSpaces :: String -> String
escapeSpaces = foldr (\c s -> if isSpace c then '\\':c:s else c:s) ""
type Suffix = String
data Direction = Forwards | Backwards
reslash :: Direction -> FilePath -> FilePath
reslash d = f
where f ('/' : xs) = slash : f xs
f ('\\' : xs) = slash : f xs
f (x : xs) = x : f xs
f "" = ""
slash = case d of
Forwards -> '/'
Backwards -> '\\'
makeRelativeTo :: FilePath -> FilePath -> FilePath
this `makeRelativeTo` that = directory </> thisFilename
where (thisDirectory, thisFilename) = splitFileName this
thatDirectory = dropFileName that
directory = joinPath $ f (splitPath thisDirectory)
(splitPath thatDirectory)
f (x : xs) (y : ys)
| x == y = f xs ys
f xs ys = replicate (length ys) ".." ++ xs
abstractConstr :: String -> Constr
abstractConstr n = mkConstr (abstractDataType n) ("{abstract:"++n++"}") [] Prefix
abstractDataType :: String -> DataType
abstractDataType n = mkDataType n [abstractConstr n]
charToC :: Word8 -> String
charToC w =
case chr (fromIntegral w) of
'\"' -> "\\\""
'\'' -> "\\\'"
'\\' -> "\\\\"
c | c >= ' ' && c <= '~' -> [c]
| otherwise -> ['\\',
chr (ord '0' + ord c `div` 64),
chr (ord '0' + ord c `div` 8 `mod` 8),
chr (ord '0' + ord c `mod` 8)]
hashString :: String -> Int32
hashString = foldl' f golden
where f m c = fromIntegral (ord c) * magic + hashInt32 m
magic = fromIntegral (0xdeadbeef :: Word32)
golden :: Int32
golden = 1013904242
hashInt32 :: Int32 -> Int32
hashInt32 x = mulHi x golden + x
mulHi :: Int32 -> Int32 -> Int32
mulHi a b = fromIntegral (r `shiftR` 32)
where r :: Int64
r = fromIntegral a * fromIntegral b
#if __GLASGOW_HASKELL__ >= 800
type HasCallStack = GHC.Stack.HasCallStack
#elif MIN_VERSION_GLASGOW_HASKELL(7,10,2,0)
type HasCallStack = (?callStack :: GHC.Stack.CallStack)
#else
type HasCallStack = (() :: Constraint)
#endif
#if DEBUG
type HasDebugCallStack = HasCallStack
#else
type HasDebugCallStack = (() :: Constraint)
#endif
#if __GLASGOW_HASKELL__ >= 800
prettyCurrentCallStack :: HasCallStack => String
prettyCurrentCallStack = GHC.Stack.prettyCallStack GHC.Stack.callStack
#elif MIN_VERSION_GLASGOW_HASKELL(7,10,2,0)
prettyCurrentCallStack :: (?callStack :: GHC.Stack.CallStack) => String
prettyCurrentCallStack = GHC.Stack.showCallStack ?callStack
#else
prettyCurrentCallStack :: HasCallStack => String
prettyCurrentCallStack = "Call stack unavailable"
#endif
data OverridingBool
= Auto
| Always
| Never
deriving Show
overrideWith :: Bool -> OverridingBool -> Bool
overrideWith b Auto = b
overrideWith _ Always = True
overrideWith _ Never = False