/src/Util.hs

http://github.com/Eelis/geordi · Haskell · 526 lines · 365 code · 137 blank · 24 comment · 27 complexity · 3a7173533af08debcc7c9103fcac402b MD5 · raw file

  1. {-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, PatternGuards, DeriveDataTypeable, OverlappingInstances, FlexibleContexts, FunctionalDependencies #-}
  2. module Util (module Data.SetOps, module Prelude.Unicode, module Util) where
  3. import qualified System.Posix.IO
  4. import qualified Data.Monoid
  5. import qualified Prelude
  6. import qualified Data.List as List
  7. import qualified Data.List.NonEmpty as NeList
  8. import Data.Maybe (listToMaybe, mapMaybe, fromMaybe)
  9. import Data.Monoid (Monoid(..))
  10. import Data.Semigroup (Semigroup(..))
  11. import Data.List (sortBy, minimumBy, isPrefixOf, tails, stripPrefix)
  12. import Data.List.NonEmpty (NonEmpty(..))
  13. import Data.Char (isSpace, isAlphaNum, toLower, toUpper)
  14. import Data.Function (on)
  15. import Data.Foldable (Foldable, toList, any)
  16. import Data.Generics (Data, Typeable)
  17. import Data.Traversable (mapM)
  18. import Control.Exception (bracket, evaluate)
  19. import Control.Arrow (Arrow, (>>>), arr, first, second, (&&&))
  20. import Control.Monad (liftM2, when)
  21. import Control.Monad.State (MonadState, modify, StateT(..))
  22. import Control.Monad.Reader (ReaderT(..))
  23. import Control.Monad.Trans.Class (lift)
  24. import Control.Monad.Trans.Reader as Reader
  25. import Control.DeepSeq (NFData, rnf)
  26. import System.Posix.Types (Fd(..))
  27. import System.IO (Handle, hClose)
  28. import Control.Applicative (Applicative(..))
  29. import Prelude hiding ((.), mapM, any)
  30. import Prelude.Unicode hiding ((), ())
  31. import Data.SetOps
  32. -- IO resources
  33. class IOResource a where dealloc :: a IO ()
  34. withResource :: IOResource a IO a (a IO b) IO b
  35. withResource x = bracket x dealloc
  36. instance IOResource Handle where dealloc = hClose
  37. instance IOResource Fd where dealloc = System.Posix.IO.closeFd
  38. instance (IOResource x, IOResource y) IOResource (x, y) where
  39. dealloc (x, y) = dealloc x >> dealloc y
  40. -- Conversions
  41. class Convert a b where convert :: a b
  42. instance Convert a a where convert = id
  43. instance (Functor f, Convert a b) Convert (f a) (f b) where convert = fmap convert
  44. instance (Convert x x', Convert y y') Convert (Either x y) (Either x' y') where
  45. convert = either (Left . convert) (Right . convert)
  46. -- List utilities
  47. splitBy :: (a -> Bool) -> [a] -> [[a]]
  48. splitBy _ [] = [[]]
  49. splitBy f (x:xs)
  50. | f x = [] : splitBy f xs
  51. | y:ys <- splitBy f xs = (x:y):ys
  52. | otherwise = undefined
  53. total_tail :: [a] [a]
  54. total_tail [] = []
  55. total_tail (_ : t) = t
  56. stripSuffix :: String String Maybe String
  57. stripSuffix x y = reverse . stripPrefix (reverse x) (reverse y)
  58. takeBack :: Int [a] [a]
  59. takeBack n = reverse . take n . reverse
  60. sortByProperty :: Ord b (a b) [a] [a]
  61. sortByProperty f = sortBy $ \x y compare (f x) (f y)
  62. findMaybe :: (a Maybe b) [a] Maybe b
  63. findMaybe f = listToMaybe . mapMaybe f
  64. elemBy :: (a a Bool) a [a] Bool
  65. elemBy f x = or . (f x .)
  66. none :: Foldable t (a Bool) t a Bool
  67. none p = not . any p
  68. maybeLast :: [a] Maybe a
  69. maybeLast [] = Nothing
  70. maybeLast [x] = Just x
  71. maybeLast (_:t) = maybeLast t
  72. maybeLastAndRest :: [a] Maybe ([a], a)
  73. maybeLastAndRest [] = Nothing
  74. maybeLastAndRest (h:t) = maybe (Just ([], h)) (Just . first (h:)) (maybeLastAndRest t)
  75. recognize :: Eq a a b (a b) (a b)
  76. recognize a b f = \x if a == x then b else f x
  77. replace :: Eq a a a [a] [a]
  78. replace x y = map $ recognize x y id
  79. replaceWithMany :: Eq a a [a] [a] [a]
  80. replaceWithMany x y = concatMap $ recognize x y (:[])
  81. erase_indexed :: [Int] [a] [a]
  82. erase_indexed i l = f 0 l
  83. where
  84. f _ [] = []
  85. f n (_:t) | n i n - length l i = f (n + 1) t
  86. f n (h:t) = h : f (n + 1) t
  87. count :: (a Bool) [a] Int
  88. count p = length . filter p
  89. length_ge :: Int [a] Bool
  90. length_ge 0 _ = True
  91. length_ge n (_:t) = length_ge (n-1) t
  92. length_ge _ _ = False
  93. -- length_ge is lazy in its list argument, which length l n is not.
  94. take_atleast :: Int (a Int) [a] [a]
  95. take_atleast _ _ [] = []
  96. take_atleast n _ _ | n 0 = []
  97. take_atleast n m (h:t) = h : take_atleast (n - m h) m t
  98. replaceInfixM :: Eq a [a] [a] [a] Maybe [a]
  99. replaceInfixM what with l = (\(pre, post) pre ++ with ++ post) . stripInfix what l
  100. replaceInfix :: Eq a [a] [a] [a] [a]
  101. replaceInfix what with l = fromMaybe l (replaceInfixM what with l)
  102. replaceAllInfix :: Eq a [a] [a] [a] [a]
  103. replaceAllInfix what with l | Just r stripPrefix what l = with ++ replaceAllInfix what with r
  104. replaceAllInfix what with (h:t) = h : replaceAllInfix what with t
  105. replaceAllInfix _ _ [] = []
  106. stripInfix :: Eq a [a] [a] Maybe ([a], [a])
  107. stripInfix p s | Just r stripPrefix p s = Just ([], r)
  108. stripInfix p (h:t) = first (h:) . stripInfix p t
  109. stripInfix _ _ = Nothing
  110. partitionMaybe :: (a Maybe b) [a] ([a], [b])
  111. partitionMaybe p = foldr (\x maybe (first (x:)) (second . (:)) (p x)) ([], [])
  112. pairs :: [a] [(a, a)]
  113. pairs (x:y:z) = (x,y) : pairs z
  114. pairs _ = []
  115. mapHead :: (a -> a) -> [a] -> [a]
  116. mapHead _ [] = []
  117. mapHead f (x:xs) = f x : xs
  118. findM :: Monad m (a m Bool) [a] m (Maybe a)
  119. findM _ [] = return Nothing
  120. findM p (x:xs) = do
  121. b p x
  122. if b then return (Just x) else findM p xs
  123. safeNth :: Int [a] Maybe a
  124. safeNth n = listToMaybe . if 0 n then drop n else drop (-n - 1) . reverse
  125. -- Non-empty lists
  126. type NeList = NeList.NonEmpty
  127. neElim :: NeList a (a, [a])
  128. neElim = NeList.head &&& NeList.tail
  129. neFilter :: (a Bool) NeList a [a]
  130. neFilter p = filter p . toList
  131. prefixNeList :: [a] NeList a NeList a
  132. prefixNeList [] = id
  133. prefixNeList (h:t) = (h :|) . (t ++) . toList
  134. neInitLast :: NeList a ([a], a)
  135. neInitLast = ((reverse . snd) &&& fst) . neElim . NeList.reverse
  136. neHomogenize :: (Functor m, Monad m) (a m b) NeList (Either a b) m (Either (NeList a) (NeList b))
  137. neHomogenize f l = case NeList.tail l of
  138. [] return $ either (Left . return) (Right . return) (NeList.head l)
  139. h:t do
  140. ht neHomogenize f $ h :| t
  141. case (NeList.head l, ht) of
  142. (Left x, Left y) return $ Left $ NeList.cons x y
  143. (Right x, Right y) return $ Right $ NeList.cons x y
  144. (Left x, Right y) Right `fmap` (`NeList.cons` y) `fmap` f x
  145. (Right x, Left y) Right `fmap` NeList.cons x `fmap` mapM f y
  146. -- Test utilities
  147. fail_test :: (Show a, Show b) String a b IO ()
  148. fail_test n x y = do
  149. putStr "Test failed: "; putStrLn n
  150. putStr "Expected: "; print x
  151. putStr "Actual: "; print y
  152. putNewLn
  153. fail "test failure"
  154. test_cmp :: (Eq a, Show a) String a a IO ()
  155. test_cmp n x y = when (x y) $ fail_test n x y
  156. -- Finite
  157. class Finite a where all_values :: [a]
  158. instance (Finite a, Finite b) Finite (Either a b) where
  159. all_values = Left . all_values ++ Right . all_values
  160. instance (Enum a, Bounded a) Finite a where all_values = enumFrom minBound
  161. -- Ordinals
  162. newtype Ordinal = Ordinal { ordinal_carrier :: Int }
  163. instance Show Ordinal where
  164. show (Ordinal n) = case n of
  165. 0 "first"; 1 "second"; 2 "third"; 3 "fourth"; 4 "fifth"
  166. 5 "sixth"; 6 "seventh"; 7 "eighth"; 8 "ninth"; 9 "tenth"
  167. _ "<other ordinal>"
  168. instance Invertible Ordinal where
  169. invert (Ordinal r) | r 0 = Ordinal (-r - 1)
  170. invert o = o
  171. -- Cardinals
  172. cardinals :: [String]
  173. cardinals = words "zero one two three four five six seven eight nine ten"
  174. -- Misc English/textual
  175. indefinite :: String String
  176. indefinite x = (if isVowel (head x) then "an " else "a ") ++ x
  177. multiplicative_numeral :: Int String
  178. multiplicative_numeral i = case i of
  179. 1 "once"; 2 "twice"; 3 "thrice"
  180. n show n ++ " times"
  181. isVowel :: Char Bool
  182. isVowel = ( "aeoiu")
  183. comma_enum :: String [String] String
  184. comma_enum _ [] = ""
  185. comma_enum _ [x] = x
  186. comma_enum a [x, y] = x ++ (if length x > 25 then ", " else " ") ++ a ++ " " ++ y
  187. comma_enum a [x, y, z] = x ++ ", " ++ y ++ ", " ++ a ++ " " ++ z
  188. comma_enum z (x : y) = x ++ ", " ++ comma_enum z y
  189. commas_and, commas_or :: [String] String
  190. commas_and = comma_enum "and"
  191. commas_or = comma_enum "or"
  192. capitalize :: String String
  193. capitalize (h:t) = toUpper h : t
  194. capitalize [] = []
  195. strip :: String String
  196. strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse
  197. caselessStringEq :: String String Bool
  198. caselessStringEq a b = (toLower . a) == (toLower . b)
  199. plural :: String String
  200. plural "body" = "bodies"
  201. plural "slash" = "slashes"
  202. plural "backslash" = "backslashes"
  203. plural "ellipsis" = "ellipses"
  204. plural s = s ++ "s"
  205. -- Inversion
  206. class Invertible a where invert :: a a
  207. instance (Functor f, Invertible a) Invertible (f a) where invert = fmap invert
  208. -- Arrow utilities
  209. snd_unit :: Arrow x x () b x c (c, b)
  210. snd_unit f = arr (\c (c, ())) >>> second f
  211. liftA2 :: Arrow a (c c' → d) → a b c → a b c' a b d
  212. liftA2 f a b = (a &&& b) >>> arr (uncurry f)
  213. -- Options
  214. class Option a where
  215. short :: a Maybe Char
  216. long :: a String
  217. show_long_opt :: Option o o String
  218. show_long_opt = ("--" ++) . long
  219. show_long_opts :: Option o [o] String
  220. show_long_opts = concat . List.intersperse " " . map show_long_opt
  221. instance (Option a, Option b) Option (Either a b) where
  222. short = either short short; long = either long long
  223. -- EitherOrBoth
  224. data EitherOrBoth a b = LeftOnly a | RightOnly b | Both a b
  225. instance (Show a, Show b) Show (EitherOrBoth a b) where
  226. show (LeftOnly a) = "(LeftOnly " ++ show a ++ ")"
  227. show (RightOnly a) = "(RightOnly " ++ show a ++ ")"
  228. show (Both a b) = "(Both " ++ show a ++ " " ++ show b ++ ")"
  229. -- Phantom
  230. data Phantom a = Phantom
  231. -- Approximate matching
  232. type Cost = Float
  233. data Op a = SkipOp a | InsertOp a | EraseOp a | ReplaceOp a a
  234. data OpsWithCost a = OpsWithCost [Op a] Cost
  235. instance Semigroup (OpsWithCost a) where
  236. OpsWithCost l c <> OpsWithCost l' c' = OpsWithCost (l ++ l') (c + c')
  237. instance Monoid (OpsWithCost a) where
  238. mempty = OpsWithCost [] 0
  239. ops_cost :: OpsWithCost a Cost
  240. ops_cost (OpsWithCost _ c) = c
  241. opsWithCost :: (Op a Cost) [Op a] OpsWithCost a
  242. opsWithCost co ops = OpsWithCost ops (sum $ map co ops)
  243. addOp :: (Op a Cost) Op a OpsWithCost a OpsWithCost a
  244. addOp co op (OpsWithCost ops c) = OpsWithCost (op : ops) (c + co op)
  245. is_insertOp :: Op a Bool
  246. is_insertOp (InsertOp _) = True
  247. is_insertOp _ = False
  248. approx_match :: Eq a (Op a Cost) [a] [a] [(OpsWithCost a, Int, Int)]
  249. approx_match co pattern text =
  250. sortBy (\(x,_,_) (y,_,_) compare (ops_cost x) (ops_cost y)) $
  251. zipWith (\owc@(OpsWithCost o _) z (owc, z, count (not . is_insertOp) o)) r [0..]
  252. where
  253. r = foldl f (replicate (length text + 1) mempty) (tail $ reverse $ tails pattern)
  254. -- r!!n contains the cheapest cost and corresponding replace-length of replacing the pattern at position n in the text.
  255. -- the nth intermediate list in r's fold stores at position p the cheapest cost and corresponding replace-length of matching the the last n elements of the pattern at position p in the text.
  256. f v pattern_tail = foldl g [opsWithCost co (map InsertOp pattern_tail)] [length text, length text - 1 .. 1]
  257. where
  258. c = head pattern_tail
  259. g w m = minimumBy (compare `on` ops_cost) candidates : w
  260. where
  261. d = text !! (m - 1)
  262. candidates =
  263. [ addOp co (if c == d then SkipOp c else ReplaceOp c d) (v!!m)
  264. , addOp co (InsertOp c) (v!!(m - 1))
  265. , addOp co (EraseOp d) (head w)
  266. ]
  267. levenshtein :: String String Float
  268. levenshtein s t = d !! length s !! length t
  269. where
  270. d = [[ distance m n | n [0 .. length t]] | m [0 .. length s]]
  271. distance :: Int Int Float
  272. distance i 0 = fromIntegral i
  273. distance 0 j = fromIntegral j
  274. distance i j = minimum [d!!(i-1)!!j+1, d!!i!!(j-1)+1, d!!(i-1)!!(j-1) + (if s!!(i-1)==t!!(j-1) then -0.4 else 1)]
  275. -- Misc misc
  276. prefixError :: String Either String a Either String a
  277. prefixError _ (Right x) = Right x
  278. prefixError s (Left s') = Left (s ++ s')
  279. isIdChar :: Char Bool
  280. isIdChar = isAlphaNum .. (== '_')
  281. instance (Functor m, Monad m) Applicative m where pure = return; (<*>) = liftM2 ($)
  282. full_evaluate :: NFData a a IO a
  283. full_evaluate x = do () evaluate (rnf x); return x
  284. -- evaluate only evaluates up to WHNF.
  285. readFileNow :: FilePath IO String
  286. readFileNow f = readFile f >>= full_evaluate
  287. -- Useful when, for example, one needs to read from a file before performing a chroot after which the file is no longer accessible.
  288. (.) :: Functor f (a b) f a f b
  289. (.) = fmap
  290. infixr 9 .
  291. () :: (Functor f, Functor g) (a b) (f (g a) f (g b))
  292. x y = (x .) . y
  293. infixr 9
  294. kibi, mebi :: Integral a a
  295. kibi = 1024
  296. mebi = kibi * kibi
  297. readEither :: Read a String Either String a
  298. readEither s
  299. | [(x, r)] reads s, all isSpace r = return x
  300. | otherwise = throwError "parse failure"
  301. readTypedFile :: Read a FilePath IO a
  302. readTypedFile f = either (const $ fail $ "parsing \"" ++ f ++ "\"") return =<< readEither . readFile f
  303. maybeM :: Monad m Maybe a (a m ()) m ()
  304. maybeM m a = maybe (return ()) a m
  305. msapp :: (Data.Monoid.Monoid a, MonadState a m) a m ()
  306. msapp = modify . flip Data.Monoid.mappend
  307. (..), (..) :: (a Bool) (a Bool) (a Bool)
  308. (f .. g) x = f x g x
  309. (f .. g) x = f x g x
  310. -- In applicative notation, these could be written: f .. g = [[ f g ]].
  311. orElse :: Maybe a a a
  312. orElse (Just x) _ = x
  313. orElse Nothing x = x
  314. apply_if :: Bool (a a) (a a)
  315. apply_if b f = if b then f else id
  316. putNewLn :: IO ()
  317. putNewLn = putStrLn ""
  318. (<<) :: Monad m m a m b m a
  319. x << y = x >>= \z y >> return z
  320. (>+>) :: (Monad m, Monoid n) m n m n m n
  321. (>+>) = liftM2 mappend
  322. parsep :: Char
  323. parsep = '\x2029' -- U+2029 PARAGRAPH SEPARATOR
  324. classify_diagnostic :: String -> Maybe String
  325. classify_diagnostic s
  326. | "warning:" `isPrefixOf` s = Just "warning"
  327. | "error:" `isPrefixOf` s = Just "error"
  328. | "Error:" `isPrefixOf` s = Just "error"
  329. | "fatal error:" `isPrefixOf` s = Just "error"
  330. | "internal compiler error:" `isPrefixOf` s = Just "error"
  331. | otherwise = Nothing
  332. describe_new_output :: [String] String String
  333. describe_new_output prev new
  334. | length new 20 = new
  335. | otherwise = (!! length (takeWhile (== new) prev)) $ cycle
  336. [ new
  337. , "Same " ++ thing ++ "."
  338. , "Still same " ++ thing ++ "."
  339. , "Again, same " ++ thing ++ "."
  340. , "Same " ++ thing ++ "."
  341. , "Give up already."
  342. ]
  343. where thing = classify_diagnostic new `orElse` "output"
  344. mapState' :: Monad y ⇒ (x → x) → StateT x y ()
  345. mapState' f = StateT $ \s → return ((), f s)
  346. data TriBool = Definitely | Indeterminate | DefinitelyNot deriving (Data, Typeable, Eq)
  347. newtype MaybeEitherString a = MaybeEitherString (Maybe (Either String a)) deriving (Show, Typeable)
  348. instance Monad MaybeEitherString where
  349. return = MaybeEitherString . return . return
  350. MaybeEitherString Nothing >>= _ = MaybeEitherString Nothing
  351. MaybeEitherString (Just (Left e)) >>= _ = MaybeEitherString $ Just $ Left e
  352. MaybeEitherString (Just (Right x)) >>= f = f x
  353. fail = MaybeEitherString . return . Left
  354. instance Functor MaybeEitherString where
  355. fmap f (MaybeEitherString (Just (Right x))) = MaybeEitherString $ Just $ Right $ f x
  356. fmap _ (MaybeEitherString (Just (Left e))) = MaybeEitherString $ Just $ Left e
  357. fmap _ (MaybeEitherString Nothing) = MaybeEitherString Nothing
  358. instance MyMonadError [Char] MaybeEitherString where
  359. throwError = MaybeEitherString . Just . Left
  360. catchError = error "sorry, not implemented"
  361. type E = Either String
  362. nothingAsError :: String Maybe a E a
  363. nothingAsError s = maybe (Left s) return
  364. or_fail :: MyMonadError String m E a m a
  365. or_fail = either throwError return
  366. strip_utf8_bom :: String String
  367. strip_utf8_bom ('\239':'\187':'\191':s) = s
  368. strip_utf8_bom s = s
  369. instance MyMonadError [Char] Maybe where
  370. throwError = const Nothing
  371. catchError Nothing f = f "error"
  372. catchError m _ = m
  373. propagateE :: Monad m E a (a m (E b)) m (E b)
  374. propagateE (Left e) _ = return $ Left e
  375. propagateE (Right x) f = f x
  376. class Monad m => MyMonadError e m | m -> e where
  377. throwError :: e -> m a
  378. catchError :: m a -> (e -> m a) -> m a
  379. instance MyMonadError e (Either e) where
  380. throwError = Left
  381. Left l `catchError` h = h l
  382. Right r `catchError` _ = Right r
  383. instance MyMonadError e m => MyMonadError e (ReaderT r m) where
  384. throwError = lift . throwError
  385. catchError = liftCatch catchError
  386. -- Natural applications
  387. class Apply a b c | a b c where apply :: a b c
  388. class MaybeApply a b where mapply :: (Functor m, MyMonadError String m) a b m b
  389. instance Apply a b b Apply (Maybe a) b b where apply m x = maybe x (flip apply x) m